# Журнал прогресса > **⟶ ТЕКУЩЕЕ СОСТОЯНИЕ** (на 2026-09-07, голова D39.225 — КУРС: движок и платформа до «работает и отдаёт результат», фронт ЗАМОРОЖЕН и P7 его НЕ размораживает (D39.147). **ОЧЕРЕДЬ №23** (единственный носитель — здесь; роль передана 06.09, №22 закрыт нотой передачи D39.217; ⚠ испр. 06.09: коммит передачи `c992ee5` бампнул голову и НЕ тронул номер — гейта на номер очереди нет вовсе, `counts.py` сверяет только голову, поэтому носитель разошёлся молча). ⚠ **ЗАКАЗ ВЛАДЕЛЬЦА 01.09 — ПЕРВЫМ:** (0а) **ревизия документации на ПРОТУХШЕЕ** — по всем зонам, не только тронутым; (0б) **планы доработок в БЭКЕНД и ПЛАТФОРМУ** по остатку бэклога и регистра; (0в) **вынос неактуального в АРХИВ** (`docs/archive/`, `platform/docs/archive/`) — за сутки 31.08 закрыто много, и часть носителей стала историей. ⚠ Трезвость по масштабу (пере-считано 02.09): **90** живых дока в `docs/` (пере-счёт 04.09: `find docs -name '*.md' -not -path 'docs/archive/*' | wc -l`), 8 в `platform/docs`, 9 в `backend/docs` — ⚠ из 94 ВРЕМЕННЫЙ остался ОДИН (`DOC_CLEANUP_PLAN`, живой до закрытия батчей Б14/Б15/Б17); два прежних временных уехали в `archive/reports/` 02.09; счёт бэклога — бюллетенем ниже, открытых рядов регистра платформы — 112 (major 3), всего рядов 465 (пере-счёт `python3 docs/scripts/counts.py`; с 04.09 оба числа под гардом `--check`, прежние 95/3 разошлись молча) ⚠ (ревизией 02.09 ряды **154** и **157** переведены из «скоро» в «когда-нибудь»: их гейтом стоял первый холодный прогон, он ОТРАБОТАЛ 31.08 и оба предусловия оказались другими — разбор в самих ячейках, ни одна НЕ закрыта). ⚠ Числа доков `counts.py` НЕ сторожит — при переносе файлов пере-считывать руками командой `find docs -name '*.md' -not -path 'docs/archive/*' | wc -l`. ⚠ И предупреждение о МЕТОДЕ, купленное сменой №21: «выглядит протухшим» ≠ «протухло». Три факта оркестратора опровергнуты ЗАМЕРОМ сессий, а якоря `15-money-path.md` в девяти случаях из двенадцати РОДИЛИСЬ верными и сгнили дрейфом — то есть ревизия обязана быть исполнением, а не чтением. ⚠ **ОЧЕРЕДЬ, унаследованная от №21** (три лендинга 31.08 — секция «СОСТОЯНИЕ ПАКОВ» ниже): **(1) ~~РАЗРЫВ ЦИКЛА~~ ЗАМКНУТ ЖИВЬЁМ 04.09** — пользователь получил EPUB настоящего ПЛАТНОГО перевода ЧЕРЕЗ API, `epubcheck` 5.3.0 на СКАЧАННОМ файле 0/0/0/0 (книга `bk_SS5VES2JELESJSTR`, потрачено $0.278319 из гранта $0.60 при потолке пака $1.5, санкция D39.189). Дверь выдачи построена и проверена исполнением: `202`+`Location`, поллинг с `Retry-After`, Range 206 · второй клиент 200 · аноним 401 · чужая книга 404, TTL с GC, идемпотентность третьего создающего вызова. Все ТРИ сценария строки 216 предъявлены живьём (подпись банка · halt на потолке с exit 4 · `409 run_not_resumable/ceiling_reached` и лечение новым прогоном). > ⛔ **ПЯТЬ ПОТОКОВ РАБОТЫ — состояние на 07.09 (пере-снято лендингами смены №23).** > **(1) ПОЛИГОН — «ремонт прибора»** (`docs/POLYGON_INSTRUMENT_REPAIR_SESSION_PROMPT.md`, строки 319 · 300 · 265 · 143): > ⚠ **ЕДИНСТВЕННЫЙ ПОТОК, НЕ СДВИНУВШИЙСЯ ЗА СМЕНУ — сессия по промту так и не стартовала.** Блокирующая линза > слепого чтения меряет верность ЧЕРНОВИКУ, а судимой руке предписано отходить от него по исходнику (`D39.215` п.3) > ⇒ **фаза Д ПРИОСТАНОВЛЕНА до его лендинга**: иначе покупаем числа, которые ничего не значат. > **(2) БЭКЕНД — «закон банка честно»: ✅ ЗАЛЕНДЕН 07.09, акт `D39.222`** (`5092ae3` + `0ae9e8a` + `bc03fc0`). Строки > 267 и 318 закрыты, у 320 исполнена половина (а). Шесть кругов самопроверки, 43 находки в собственной работе. > Живой остаток зоны — строки **333–339** (шов-близнец и пять описаний, лгущих оператору) и 320(б). > **(3) ПЛАТФОРМА — «деньги и правда»: ✅ ЗАЛЕНДЕНА 07.09, акт `D39.221`, контрактный минор `0.13.0`** (`fda0679` + > `3d90943`). Строки 285 · 305 · 325 закрыты. ⚠ **Синхронный разрез приёма принят ПОСТРОЕННЫМ, НО НЕ ГОТОВЫМ** — > сработало правило остановки (9 major из 11 в одном механизме), десять пунктов несёт строка **332**; ложный > инвариант бюджета заландён осознанно (окно лжи 8 секунд при дефолте в 16 минутах, ломается идемпотентность). > **(4) ДИЗАЙН-ПАК 161 — ✅ НАПИСАН 07.09** (`docs/CHAPTER_STRUCTURE_DESIGN_SESSION_PROMPT.md`, `7f84c8d`), прошёл оба > рубежа. ⚠ **НЕ ВЫДАН: новый пак идёт НОВОЙ сессии, обе ночные отработали** — запуск за владельцем. > **(5) ТЕХДОЛГ БЭКЕНДА — разбор `research/33` в трекер: ✅ ЗАЛЕНДЕН 07.09, акт `D39.224`.** Заведены строки > **344–350**, дописки в 86/114/119/182/224; «переписать» не получил ни один из одиннадцати долгов. Ратифицированы > ПОРЯДОК (шаг 0 параллельно дизайну 161 → шаги 2+3 ОДНИМ окном перенарезки, wire-очередь **182** ложится в него > же → шаг 4 аддитивно) и ФОРМА запретов (жёсткие — только под ратифицированной базой, прочее — условия с > механизмом, чтобы не спорить с дизайн-паком). **Пак шага 0 ✅ ЗАЛЕНДЕН 07.09, акт `D39.225`** (две смены поведения названы, вторая денежная: прогон по арму теперь покупает банковый контур). Промт был — > `docs/BACKEND_GATES_NOT_PROSE_SESSION_PROMPT.md`, $0 и снапшот-нейтрально: строки 344 · 345 · 346(а) · 348 · 224, > попутно 349/350. Прошёл оба рубежа; вход зоны зелёный (`go test ./... -count=1` → 19 `ok`, 0 FAIL, 4 пакета без > тестов). ⚠ Единственная заказанная смена поведения — экспорт банка на стопе, и её форма ЗАДАНА аддитивной: > перенос засева в ветку стопа запрещён явно (уводит НЕПОДПИСАННЫЕ строки в глоссарий, а те инъектируются > законом ⇒ двигают `memory_version`). Снапшот-нейтральность требуется доказать байт-равенством снапшотов. > ⛔ **ЧТО ЖДЁТ СЛОВА ВЛАДЕЛЬЦА, поимённо:** строка **340** — сужение входа действует только на синхронной ветви, > при деплойном классе книга одним полотном попадает в библиотеку МОЛЧА, и закрыть нечем без пятой причины отказа > (`source_unreadable` терминален и УДАЛЯЕТ исходник) · строка **326** — критерия впуска в дереве нет, консьерж > против самообслуживания · обязательный ВТОРОЙ круг селф-ревью (первая половина того же слова подтверждена как > РЕКОМЕНДАЦИЯ, `D39.220`; вторая не подтверждена, улика в её пользу — ниже в этом же листе). > ⚠ **Зоны параллельны по норме проекта; ограничение — пропускная способность ПРИЁМКИ оркестратора: сериализуй > ЛЕНДИНГИ, не старты.** ⚠ Зеркало фронта — `0.2.3` против канона **`0.13.0`** (одиннадцать миноров), зона заморожена. > ✅ **ПОЧИНЕНО 05.09 ЛЕНДИНГОМ `616a8e4` (пак «денежный стоп», акт приёмки **D39.206**; ⚠ испр.: раньше здесь стояла D39.203 — это нота ВЛАДЕЛЬЦА про «сколько добавить», а не акт) — ниже до-паковая археология, читать как историю.** Отказ резервации больше не роняет волну: он ЗАЩЁЛКИВАЕТ её (новое не стартует, допущенное дорабатывается), а обязательный вызов ЖДЁТ settle, когда settle может помочь. ⇒ **порог «книга короче десяти глав не переводится» СНЯТ**; остаточный пол — одна резервация (~$0.07 ≈ 3 главы), и он ВЫВЕДЕН, а не замерен (замер — $0.15-прогон пятиглавой книги, передан полигону). ⚠ Разбор эрратой — `architecture/15-money-path.md`, греп `ЭРРАТА 05.09`. ⚠ **Эта строка сутки стояла непоправленной ПОСЛЕ лендинга и по ней оркестратор предупредил владельца о снятой стене как о действующей** — канон, не обновлённый лендингом, врёт громче отсутствующего. **НО КНИГУ ЧЕРЕЗ API НЕЛЬЗЯ БЫЛО ДОВЕСТИ ДО КОНЦА — найдено прогоном 04.09 и воспроизведено дважды.** Прирост потолка на прогон = `chaptersLeft × $0.03` (ставка `DefaultPerChapter`, занижена ×4.47 — D39.179 п.1), и после первой готовой главы это $0.27, тогда как движок при `waves.workers: 4` резервирует под редакторский шаг ~$0.28 ⇒ **отказ резервации, прогон встаёт, книга не двигается**. Два прогона подряд дали одно и то же: `committed` не сдвинулся, холд вернулся. ⇒ **занижение ставки — не «шкала короче», а СТОП ПРОДУКТА: с какого-то момента каждая следующая покупка не покупает ничего.** Лечить придётся согласованно двумя сторонами (ставка платформы + резерв движка под шаг с параллельными воркерами), носитель — ряд регистра зоны, вес `major` **за недостижимость продукта, а не за деньги**: сам стоп НЕ ЖЖЁТ ничего — замер платформы 04.09 показал отмену ДО ухода запроса (латентность 20–31 мс, `model_actual` пуст, токенов ноль), и вся книга сходится до микро-доллара по трём источникам (`request_log` 0.278319 · `spend.committed_usd` 0.278318752 · платформенный `committed` 278319 микро). > ⛔ **ЗАТО HALT НА ПРОГОНЕ, КОТОРЫЙ ПРОДВИНУЛСЯ, ЖЖЁТ — отдельная находка того же прогона и свежая датированная точка строки 78 («леджер = НИЖНЯЯ граница»).** Четыре редакторских вызова ушли параллельно; один дошёл ($0.063404) и своим коммитом сорвал потолок, три других отменены в тот же миг, **отработав 120756, 156469 и 156470 мс** — и легли в леджер нулём. Незаписанное ≈ **$0.05–0.19 на ОДИН halt** против $0.278 за всю книгу, то есть механизм, защищающий от перерасхода, сам создаёт неучтённый расход. ⚠ Списание провайдером НЕ доказано (биллинга у нас нет) — утверждается ровно наблюдаемое: вызовы шли 2–2.6 минуты, их цены в леджере нет. > ⇒ **Дыра НЕ в принципе, а в покрытии, и это делает её заказом, а не наблюдением** (разбор оркестратора 04.09 по коду): консервативная оценка уже построена и ратифицирована — `backend/internal/pipeline/stagerun.go`, греп `settling the reservation estimate to keep the ceiling honest` (pack-13 point-9), — но её условие требует ОТВЕТА провайдера (`resp.Usage`), а отменённый в полёте вызов ответа не получает и уходит другим путём. Направление лечения: сеттлить оценку при отмене вызова, который успел уйти; различитель — факт ухода (латентность кандидат, порог обязан быть обоснован замером, а не назначен). Половина ДВИЖКОВАЯ. ⚠ Прежняя формулировка пункта — ниже, она о состоянии ДО 04.09. Движок пишет файл с 30.08 (`tmctl build` — EPUB 3 + чистый txt, D39.175), и холодный прогон 31.08 предъявил это живьём: собранный EPUB настоящего перевода прошёл `epubcheck` 0/0/0/0 и передан владельцу. ⚠ **ЭТОТ АБЗАЦ ЗАКРЫТ 04.09 и оставлен как история:** дверь выдачи ПОСТРОЕНА и заленджена (`adf5e53`, D39.194), смонтировано **18 операций из 21** (три адреса двери: `createExport`/`getExport`/`downloadExport`), долг `П-17` зона пере-сняла. Прежняя проверка «`grep -rn 'createExport\|getExport' platform/internal/` — пусто» БОЛЬШЕ НЕ ПУСТА и как гейт не работает. Не смонтированы по-прежнему `getRun`, `updateBook`, `deleteBook` — `updateBook` несёт продуктовое следствие, строка бэклога 274 (имя книги в выданном файле не чинится ничем). **Слово «отдаёт результат» ложно по букве ТОЛЬКО платформенной половиной** (п.4) · **(2) ~~холодный прогон движка~~ ОТРАБОТАЛ 31.08, закрыт РЕШЕНИЕМ ВЛАДЕЛЬЦА «не доводить»** (отчёт — `archive/reports/COLDRUN_V16_REPORT_2026-08-31.md`, числа относятся к `065d8ac`). Потрачено **$0.436110** из санкции $0.80. ПРЕДЪЯВЛЕНО живьём: объёмный потолок · D39.158 ОБЕИМИ половинами (стоп и не-стоп) · exit 16 · строки 154/198/239/240. ⚠ ~~**Причина большой доли редактора НЕ УСТАНОВЛЕНА**~~ — **УСТАНОВЛЕНА пробой полигона 02.09 по четырём осям: РЕДАКТОР ДУМАЕТ, А НЕ ПИШЕТ.** Размышление — **77.9%** цены редактора без ручки и 45.7% с `low`; у `glm-5` с выключенным thinking — 0.0%. Замер куплен и закончен ($6.17 из $9.50). ⚠ `research/30` §2.4 того же полигона повторяет «причина не установлена» — это про ДРУГОЙ вопрос (доля роли в прогоне против доли размышления в цене роли), и различение обязано попасть в ревью-шапку 30. Доля редактора идёт с ДВУМЯ знаменателями: **49.3%** от всего прогона ($0.214865 из $0.436110) и **81.3%** внутри порции П1 (⚠ ходившее «73%» — фантом, в отчёте его нет ни разу). Следующий шаг — контролируемая проба по ЧЕТЫРЁМ осям (роли осей и три требования, купленные ошибками этого прогона, — §14 отчёта; ось `stale` НЕДОСТИЖИМА — §10 там же). ⚠ **Цена: слово владельца 31.08 — ≈$0.60, потолок $0.80, ДЕСЯТЬ глав ПОЛНОЙ цепью включая редакторскую волну.** ⚠ **КЛЮЧИ: гейт снят словом владельца 30.08, разбор двух путей — D39.176 п.6.** Живое отсюда: конвенционного `.env` НЕТ НИ У ОДНОЙ книги корпуса (заполнены только `projects/textmachine/backend/.env` и `.../eval/.env`), поэтому прогон движка обязан передавать `--keys-file` абсолютным путём и только на `translate`; для п.3 нужен ДРУГОЙ файл — `TM_PLATFORM_ENGINE_KEYS_PATH`, тоже АБСОЛЮТНЫМ путём (`platform/internal/config/config.go`, греп `must be an absolute path`). Лечение операционное и $0 — направить переменную на уже заполненный файл; проверять ПРОГОНОМ, не чтением (гардрейл `.env`) · **(3) живой сквозной прогон через API платформы** — форма манифеста, сайдкара банка и карта причин флагов сочинены платформой САМОСТОЯТЕЛЬНО. ⚠ Уточнено 01.09: гейт СНЯТ холодным прогоном, и настоящие артефакты движка теперь ЕСТЬ (каталог `books/gu-zhenren/coldrun-v16/`), но сверка вышла ТОНКОЙ: на шов реально вышло **одно значение `flag_reason` из пятнадцати** (`sanitizer_stripped`), остальные четырнадцать по-прежнему только чтением кода, а манифест против `platform/internal/ingest/manifest.go` не сверялся вовсе · **(4) дверь выдачи** — строго ПОСЛЕ (3) (⚠ слово владельца 30.08: дверь ВСЕГДА строит файл — отказ юзеру не отдаётся, неполная книга уходит с пометкой, т.е. дверь зовёт `tmctl build --partial`; отказ по умолчанию остаётся операторской ручкой CLI; D29.1(б) «fail-closed» читать как «никогда молча» — честность несут пометки) · **(5) проводка `--max-units`** — снятие гейта, а не стройка: механизм в движке стоит (D39.170), живое основание гейта — `PD-422` · **(6) разморозка фронта** — ПОСЛЕ (4): зеркало отстало на **ВОСЕМЬ** миноров (`frontend/docs/api-contract/openapi.yaml` — `0.2.3` против канона `0.10.0`, и первый из них — ЛОМАЮЩИЙ 0.3.0), **16 операций против 21**; зеркало последний раз двигали 15.08 — ⚠ ходившее «30.08» было взято из текста коммита, а не из `git log` (испр. 05.09), то есть расхождение старше на две недели; отставание ратифицировано D39.142 п.5 на время фриза и две ручки разъехались, размораживать раньше значит перегенерировать типы дважды. ⚠ **ДВА ЗАГЕЙЧЕННЫХ ТРИГГЕРА НАЖАТЫ И НЕ ОТРАБОТАНЫ — строка бэклога 237** (`go.work` · вендор-сверка эффорта `deepseek-v4-pro`; реестр `13-tech-debt-anchors.md` §Б-108). ⚠ **Состояние git — снимать КОМАНДАМИ, не чтением** (ветка `polygon` ушла вперёд, коммит здесь не цитирую): работа полигона лежит на ней и в `main` НЕ влита, а `git status -- eval/` в main-дереве пуст ПО ПОСТРОЕНИЮ и уводит в ложный вывод «работы нет»; ⚠ **«развязка git с origin» — арбитр ПЕРЕ-СНЯТ 04.09 и прежний вердикт БОЛЬШЕ НЕ ВЕРЕН:** `git merge-base --is-ancestor origin/main main` → **rc 1**, `git log main..origin/main` → `afa7700 temp` (коммит владельца 04.09, которым он передавал работу зон). Локальная линия ушла вперёд на семнадцать коммитов и содержит ВСЁ содержимое `afa7700` — оно снято `reset --soft` и заленджено раздельными зонными коммитами, — но формально ветки разошлись. Лечение — force-push рукой владельца; **не пуллить** (его же правило). ⚠ Пункт «развязка git с origin» в листе владельца ниже держится ТОЛЬКО как вопрос про force-push его рукой; утверждением о расхождении дерева он не является — арбитр этой пары именно здесь. > - ⚠ **Норма приёмки, купленная аудитом D39.167 п.1:** акт лендинга, объявивший закрытие строки регистра или бэклога, обязан быть СВЕРЕН СТАТУСОМ в тот же заход — иначе следующий пак собирается ПО РЕГИСТРУ и едет чинить построенное. Машинная половина — строка бэклога **225**. > - ⚠ **ЛЕНТА КОНТРАКТНЫХ МИНОРОВ** (что принёс каждый — телом ноты): **0.5.0** — D39.161 · **0.6.0** — D39.162/D39.163 · **0.7.0** — D39.166 · **0.8.0** — D39.169 · **0.9.0** — D39.180 · **0.10.0** — D39.194 (дверь выдачи: `downloadExport`, `failure_code` словарём, `Export.url` относительный; ⚠ читать с эрратой 04.09-в — минор был ратифицирован без своей кодовой половины и сутки жил ложным на проводе). Прожитые дампы приёмок P9/P10 — `archive/PROGRESS-2026-08-backend.md` и тела нот. > - **ЖИВОЕ:** полигон — **фаза Д ИДЁТ** (заказ 10.08; деньги санкционированы 15.08 напрямую полигону — ⚠ числа потолка в носителях расходятся, фактическую цепь сверить при лендинге петель; ja-книга `enkan_no_hate_ja`; при ратификации фазы Д в D-ноту: декой-правило + обязательный кросс-семейный опровергатель приёмки — одобрены 10.08; свежие фриз-коммиты полигона в дереве — НЕ трогать) · платформа и контракт — статус в строке выше, здесь НЕ дублируется (один носитель на факт) · **фронт ЗАМОРОЖЕН** (D39.136 п.2 + **D39.147: морозится ДАЛЬШЕ лендинга P7 — слово владельца 17.08; P7 зону НЕ размораживает, S5-промт не выдаётся, разморозка отдельным словом по достижении сквозного пути**; перечень первого касания зоны — синк зеркала на ТЕКУЩИЙ канон (отставание и его цена — п.6 очереди выше и строка бэклога 183(б)) + перегенерация типов + моки + гейт утечки конвейера + ФС-1..12 + Ф-63/Ф-28 + фразы В-11 по словарю кодов — не отменён, ждёт разморозки) · закрытые стройки эры — реестром нот `architecture/05-decisions-index.md` (D39.130–137, одна строка на ноту). > - **Открыто на владельце:** ⚠ **НОВОЕ 06.09: второй круг селф-ревью** — бэкенд-сессия передала слово владельца «после сдачи обязателен селф-ревью, и если он дал исправления — НОВЫЙ круг, проверяющий исполнением и исходный заказ, и закрытие находок предыдущего круга». Первую половину того же слова (комментарии) он подтвердил как РЕКОМЕНДАЦИЮ, про вторую не сказал ничего; в мандате самопроверки `CLAUDE.md` сегодня описан ОДИН круг. Сессии исполняют добровольно, каноном не стало. ⭐ **УЛИКА В ПОЛЬЗУ ПРАВИЛА, снятая в ту же ночь 07.09:** круг 2 бэкенд-сессии опроверг ЕЁ ЖЕ правку круга 1 — свёртка сравнения через `NormalizeSourceKey` вводила ЛОЖНООТРИЦАНИЕ (замер зоны: `ReplaceGlossary(族長 + 族长)` → `rows stored=2`, контроль на байт-равном `src` → `UNIQUE constraint failed`, то есть UNIQUE стоит на СЫРОМ `src` и обе строки инжектятся), и мутация «свернуть сравнение» до круга 2 ПЕРЕЖИВАЛА весь пакет. Один круг сдал бы тихо-зелёное. · ✅ **Развилка строки 291 ЗАКРЫТА владельцем 05.09 — `D39.204`:** отказ резервации на ретрае деградирует во ФЛАГ («пусть флагает просто как-то»); вариант «минимальная покупка ≥ `step_max_usd`» снят. ⚠ Это оказалось НЕ сменой канона: D2 уже кончается флагом, денежная ветка до него не доходит. · ✅ **Лестница D25.1 ЗАКРЫТА владельцем 05.09 — `D39.205`:** копия БЕЗ пометки = книга БЕЗ ЕДИНОГО ПРОПУСКА; любой пропуск ⇒ пометка в файле, гранулярность — ЮНИТ (пропущенный кусок главы критичен). Имя файла решено паком `7e2226a` (вычисляется при скачивании). ⚠ Прежняя редакция держала это открытым на владельце — по ней он и получил вопрос, который сам уже закрыл · лейбл главы без заголовка (сейчас цифры; словесный шаблон = одна строка `reader.txt` после ратификации К-3) (⚠ три вопроса пака ЗАКРЫТЫ словом владельца 30.08: экспорт юзеру — всегда строить, см. п.4 очереди · модель пометок подтверждена как построена — надпись о пропуске в файле, отдельный варнинг-слой в интерфейсе НЕ строим, машинный отчёт сборки остаётся внутренним носителем (дрейф) · RTL — снят до появления право-налевой целевой пары) · ⚠ **ПЛАТФОРМЕННЫЙ ЛИСТ ЗАКРЫТ СЛОВОМ ВЛАДЕЛЬЦА 30.08 — четыре ответа и их следствия ЦЕЛИКОМ телом D39.176** (квот нет · продажа не в бете · продолжение после пополнения — руками · фразы пользователя делегированы проекту с требованием интернациональности). ⚠ **Лист ПУСТ:** последний его пункт (`PD-421`, «держит ли открытый поток сессию живой») СНЯТ замером 30.08 — окно бездействия сессии **14 суток**, абсолютный срок **30** (`platform/internal/config/config.go:339`=`defaultSessionIdle`), скольжение окна идёт на любом аутентифицированном запросе, а поток теряется лишь после того, как подметён протухший ряд, то есть после ДВУХ НЕДЕЛЬ без единого действия пользователя. ⚠ Часовой интервал в этой теме — периодичность УБОРКИ, а не срок сессии (эррата 30.08-а к D39.176 п.5) · ⚠ Гейт словаря фраз — строка **204** (D39.176 п.4). ⚠ Прежний указатель «строка 148» мёртв — строку удалил `a023e39` решением владельца, восстанавливать Приложение А по ней НЕ надо · **развязка git с origin** (локальная линия ИСТИННА, force-push его рукой; не пуллить) · В-4/Ф-30 (глава без заголовка — движковая половина строка 160) · мини-проба флора 44 (одобрена, промт не выдан; число — после ре-пробы 188) · ~~подпись денежного шага 46~~ (ратифицирована D39.190 п.4: пере-снапшот батча — единым актом, цена сегодня $0) · **схема time-based DeepSeek** — рекомендация и её доводы строкой **172**(а) · **вход ратификации фазы Д:** посылка «dspro дешевле glm» в пике ПЕРЕВЁРНУТА (×1.26 дороже, D39.137 п.4) · **возражение Sol по проходу `tier` эксп-23** (довод дословно — слайс `archive/PROGRESS-2026-08-10-15.md`: Sol судил СВОЁ семейство, что запрещено D13.3; подтвердить или снять — при лендинге петель фазы Д) · фронт-вопросы зонного журнала: В-7 (плотность; держит Ф-54) · В-8 (слово состояния в дереве) · В-9 (языки интерфейса — механизм готов, ПТ-36) · Ф-38 (вкладка «Замечания»). Закрытые пункты листа — в нотах D39.136–145, здесь не держатся. > - **Сделано (сводно)** — снимок ленты закрытых эр в [archive/PROGRESS-2026-08-04-09.md](archive/PROGRESS-2026-08-04-09.md); детали — D-лог и слайсы. > - ⭐ **КУРС НА 04.09 — ПОРЯДОК РАБОТ, СОБРАННЫЙ ВЕЕРОМ ПО ВСЕМУ БЭКЛОГУ (31 агент, 46 кандидатов, шесть срезов + опровергатели + критик полноты).** ⚠ Главный результат метода, а не списка: **из 46 кандидатов бэклога опровержение пережили ДВА** — остальное трекерная инерция; а то, чего в трекере не было ВОВСЕ, оказалось тяжелее всего, что в нём есть (строки **269–275**, заведены этим же заходом). Порядок: > **(1) ЭКСПЛУАТАЦИЯ — ✅ ЗАКРЫТА ЛЕНДИНГОМ 05.09 (`7e2226a` + `3e84716`, акт D39.201): бэкапы с ПРЕДЪЯВЛЕННЫМ восстановлением, дверь для не-браузерного клиента, имя книги. Строки 269 · 270 · 274 закрыты и сняты из таблицы; ниже — история заказа.** Строка **269** бэкапов нет ни у оплаченной работы, ни у денежного реестра — ЕДИНСТВЕННАЯ находка дня без частичного исхода: одна потеря диска необратима и недоказуема · строка **270** у продукта НОЛЬ дверей: `bearerToken` объявлен и не выдаётся, живой цикл 04.09 прошёл через dev-вход, который прод отказывается запускать, фронт заморожен · строка **274** имя книги в выданном файле исходноязычное и не чинится ничем (дёшево, а ломается первое, что видит человек). > **(2) ДЕНЬГИ И ЕДИНИЦА ЗАКАЗА — РЕШЕНО 04.09 во ВТОРОЙ редакции, строки 276–283: заказ это ОБЪЁМ, объём меряется ЗНАКАМИ ИСХОДНИКА ПО ЮНИТУ (движок публикует в манифесте), «страница» — их отображение и её размер это ДАННЫЕ ЛОКАЛИ; вердикт ДО клика, сумму человек не выбирает.** ⚠ Первая редакция мерила ГЛАВАМИ и пала: глава надёжна в одном случае из трёх, дыру нашёл владелец. ⚠ Тем же вопросом вскрыта ВТОРАЯ ненадёжная единица — `character_count` считает байты файла (для EPUB — zip) и подписан у пользователя «Знаков», строка 282. ⚠ **ФОРМА ЗАКРЫТА РЕШЕНИЕМ ВЛАДЕЛЬЦА 05.09 (D39.196): баланс — ДЕНЬГАМИ и виден, ползунок потолка — деньгами, второй ползунок объёмом (главы если распозналось, знаки если нет), старт = холд.** Запрет «денег в UI» ОТОЗВАН владельцем; ждать от него больше нечего. Разбор трёх независимых чтений в `architecture/15-money-path.md` §«ОТКРЫТАЯ РАЗВИЛКА 04.09»; `PD-440`/`PD-441`. Смена единицы — амендмент **D39.84**, объявленный требующим отдельного слова ещё при вписании глав (D39.110 п.2а, «добор оркестратора»); сам владелец 28.08 назвал нынешнюю ручку «денежной ручкой с подписью главы» (**D39.165 §1**). ⚠ Смена единицы БЕЗ «сказать, когда кончилось» ухудшает продукт: стена перестаёт быть свойством книги и становится свойством ввода, то есть встречается ПЕРВЫМ действием, а не в конце. > **(3) ДЫРА ЧЕРЕЗ ПОЛЬЗОВАТЕЛЬСКУЮ ДВЕРЬ — ✅ ЗАКРЫТА ЛЕНДИНГОМ 05.09 (`81a89e9`, акт D39.206): граница `internal/membank/wirefence.go`, три точки исполнения, инвариант снова выполняется КОНСТРУКЦИЕЙ. Строка 271 закрыта и снята; ниже — история заказа.** Строка **271**: правки банка едут в system-сообщение дословно, а ратифицированный инвариант «untrusted DATA, никогда инструкции… выполняется КОНСТРУКЦИЕЙ» конструкцией больше не выполняется. Дёшево, и обязано быть закрыто ДО первого внешнего пользователя. > **(4) КАЧЕСТВО — ЦЕЛЬ №1. ⚠ ФОРМУЛИРОВКА «НЕ МОЖЕТ СТАРТОВАТЬ» БЫЛА НЕВЕРНА И СНЯТА ВЛАДЕЛЬЦЕМ (D39.198 п.5, испр. 05.09):** из четырёх названных гейтов (24 · 13а · 55 · 149) ТРИ сняты его словом, четвёртый гейтом не был. Живое здесь другое и оно в строке **275**: приоритет назван — **(1) 100% консистентность · (2) отсутствие выдумок · (3) художественность**, и он говорит не о весах рубрики, а о том, ЧЕЙ ОТКАЗ ОСТАНАВЛИВАЕТ ВЫПУСК. Классы дефектов привязываются к УЗЛАМ (банк · редактор · черновик), а не сливаются в одно взвешенное число: оно не диагностирует. ⚠ Дорогое расхождение здесь остаётся, но НЕ то: приоритет №1 сегодня кодом НЕ исполняется — доки держат порог 98%, `glossary_miss` отгружается флагом ранга 5, а приоритет №2 носителя не имеет вовсе (строка **286**). > **(5) ВТОРАЯ ПАРА ЛОМАЕТСЯ МОЛЧА — после (1)–(4), пока пара одна, цена ошибки нулевая.** Строка **272** шаблон книги один на все пары и раздаёт КАЖДОЙ книге `transcription: palladius` · строка **273** пар-шов асимметричен: нет промптов — падает громко, нет целевых ДАННЫХ — выключается молча ВМЕСТЕ С БАНКОМ, то есть книга переводится целиком за полные деньги без механизма консистентности · строки **258**/**259** через раннер нет ни одной фикстуры с не-ru целью, латинописьменной цели в репо нет вовсе. > ⚠ **Что веер НЕ менял:** горизонт (ДОБОР ИДЕАЛА → вторая пара → МАСШТАБ → пилот → ридер-IDE) остаётся тем же; переставлен ПОРЯДОК ВХОДА в него, и вход теперь эксплуатационный, а не качественный — потому что пускать пользователя некуда и нечем страховать. > - **Курс:** этапы ОБЩНОСТЬ · КАЧЕСТВО БАНКА · ПАКЕТ-ЧЕКЕРОВ · ФРОНТ-ЭРА · шов/платформа/движковые блокеры — ПРОЙДЕНЫ (D39.59–123). Хвосты курса живут строками: 16 (полная цена холодного старта; edit-волна на малых прогонах отработала и оплачена — 58 вызовов волновым драйвером 23–25.07 плюс 648 до драйвера, счёт по леджерам `~/books/gu-zhenren/**/*.db`) · coldrun-b фаза C заморожена чекпойнтом легитимно (D39.86; эталон денег/поведения — coldrun-a, read-only); развилка 0731 решена и исполнена (D39.87/91, код `553f1a3`). > - **Горизонт (D39.62/67, освежён D39.95):** **ДОБОР ИДЕАЛА** (первым прогоном: оси голоса 24 · авто-режим · цена 16; остаток арбитража банка = рецензент спорных кластеров при ре-пробе — D39.102). ⚠ **Испр. 05.09 (D39.198 п.5):** прежняя редакция держала здесь ТРИ предусловия, снятых владельцем, — жильцы ролей (149: разморозка ничего не разблокирует, пока идут доработки) · веса K1–K12 (13а: веса не нужны, мерить по узлам) · вне-претрейн чекпоинт (55: прогоняем на тех же текстах, оговорка — ограничение ВЫВОДА, а не требование новой книги) → ВТОРАЯ ПАРА живьём (ja→ru; преп 81) → МАСШТАБ → пилот Ф2.5 (гейт резюме-строки 80; строки 62–68, 85) → Ф3 ридер-IDE (69–71). **Стоячие:** ToS-триггер 25.10 · Ш-2 до go1.27 (⚠ + x/text Unicode 17 тем же тулчейном — строка 119, реестр §Б-108 справочника якорей) · платные прогоны разблокированы (проба провода — D39.97, конфиги 112 залендены). > - **Стек (полная карта роль→модель→конфиг→квирки — [STACK.md](STACK.md), D39.126):** draft deepseek-v4-flash thinking-ON `low` **⚠0731** → терминолог (та же модель) → editor deepseek-v4-pro БИЛИНГВ ИНТЕРИМ (топология ПОДТВЕРЖДЕНА при неразличимости жильцов — D39.117; закон-блок ОБЯЗАТЕЛЕН и ВНЕСЁН — D39.104 п.2, вайр-батч принят D39.199; glm-5 резерв; вахта маппинга эффорта pro — §Б-108) → судья gemini (Ф2, в движке НЕ построен — строка 33); канал B Mistral+grok; ~$0.85/ранобэ (D30.4) — ⚠ **ТРИГГЕР ПЕРЕ-КАЛИБРОВКИ СРАБОТАЛ 31.08** (испр. 02.09): платный прогон отработал и дал собственную оценку движка `projected_book_usd = 1.1377277707` на десяти главах при куплённых $0.436110; число D30.4 держать как июльское. ⚠ **Вендор-факты 13–15.08 (пере-пин ИСПОЛНЕН и ПРИНЯТ, D39.137):** таблица цен запинена ПИКОМ (flash 0.44/1.32 · pro 1.32/3.96/кэш-хит 0.044 за 1M; счёт шиппинг-c1 = 100% DeepSeek ⇒ ×4.2–4.4 в пике / ×2.1–2.2 в долине — замер по трём прогонам); ⚠ **испр. 05.09: носители про эффорт `pro` БОЛЬШЕ НЕ ПРОТИВОРЕЧАТ** — и квирки (§3г), и `STACK.md` говорят одно: ручка ДОХОДИТ до модели с вендор-апдейта 13.08. Живой остаток один — вендор-сверка маппинга и ВЕЛИЧИНА эффекта, строка **237**(б); ⚠ ВЕСА pro сменились под тем же слагом (V4-Pro-0813, класс D39.61) — вахта-риг готов (остаток 172); покупки фазы Д на deepseek до 16.08 16:00 UTC — по старым ценам. ⚠ **ВЕСЬ банковый контур (банкнота+терминолог+классификатор) ВКЛЮЧЁН в shipping-c1 с `b8154cd`** — `enabled: true` у обоих гейтов и `classify_types: true`, бюджеты по $1.00 (прежде жил только ран-локальным конфигом книги; строка 140 — ⛔ его единственный вход `mining.contrast_path` в git ОТСУТСТВУЕТ, развёртывание обязано положить артефакт, иначе контур не исполняется вовсе, носитель — строка 251; сверка STACK.md 09.08 — факт шире прежней декларации «одна банкнота»); эскалация в shipping за `budget_usd: 0` (STACK.md §примечания). > - **ЕДИНЫЙ БЭКЛОГ — отдельный файл [BACKLOG.md](BACKLOG.md)** (одна таблица, единственный трекер проекта, ID строк прежние; каждая петля обязана иметь диспозицию: решено / отложено-с-записью / отклонено; ведёт оркестратор). ⚠ **Счёт очереди — бюллетень в ШАПКЕ ТОГО ФАЙЛА, здесь копии НЕТ** (`python3 docs/scripts/counts.py`; переезд 06.09 — D39.218). > - Архивы хроники: `archive/PROGRESS-2026-07-04-10.md` (D31) · `-10-13` (D39.6-гигиена) · `-13-25` (стройка паков 11–16, rerun2) · **`-25-31` (паки 17–20 · мини-прогон · полигон-пакеты 5–8 · ToS · холодный прогон; D39.26–58)** · **`-08-01-02` (сессии №9/№10: общность · качество банка · coldrun-b · открытие фронта/платформы; D39.59–90, срез D39.105)** · **`-08-02-04` (сессии №11–№13: ручки эффорта · стандарты · контракт API · платформа P0 · банк-арбитраж; D39.91–105 + снимок шапки эры №15)** · `-08-04-09` (пинги закрытых паков эры №15) · **`-08-14-15` (закрытые бэкенд-записи №16–17: эмиттер шва · migrate · пере-пин DeepSeek; вынесено D39.139)**. Записи ниже — живой хвост (№16+, эра D39.124+; подрезка D39.139). ## 📌 СОСТОЯНИЕ ПАКОВ **Залендены и ратифицированы, приёмочные дампы — телами нот:** платформенный **P11** — D39.169 · движковый пак **«деньги»** — D39.170 · платформенный **P12** — D39.180 (вместе с контрактным минором **0.9.0**; `PD-425` закрыт им же) · бэкенд-пак **«деньги и честность выдачи»** — D39.182 (тестов 1045→1083, удалённых ноль) · **закон раскрытия** движка — D39.181, ратифицирован владельцем и применён к одиннадцати экземплярам. ✅ **ПАКИ 05.09 ОТРАБОТАНЫ И ПРИНЯТЫ ОБА С ДОФИКСОМ, промты в `archive/prompts/` с баннерами исхода, зоны свободны:** движковый «денежный стоп» — `81a89e9` + `616a8e4`, акт **D39.206** (18 находок приёмки, 6 снято, 12 устояло, 4 major — все четыре оказались УТВЕРЖДЕНИЯМИ, а не поведением); платформенный «пустить внутрь можно» — `7e2226a` + `3e84716`, акт **D39.201** (20 находок, 5 снято, 15 устояло, 5 major — ТРИ в самом механизме бэкапа). Ниже — история паков 04.09. **ПАКИ 04.09 ОТРАБОТАНЫ И ПРИНЯТЫ ОБА (испр. 05.09).** Платформенный «закрыть цикл» — `adf5e53`, **D39.194**, контрактный минор 0.10.0 тем же актом (⚠ эррата 04.09-в: минор ратифицирован БЕЗ своей кодовой половины и сутки жил ложным на проводе; починено `7e204db`). Движковый вайр-батч — приёмочный коммит **`74ffe4f`**, **D39.199**, принят С ДОФИКСОМ; строки заказа 210·113·46·134·140·184·232 ЗАКРЫТЫ и сняты из таблицы, найденное вне карты отчёта заведено строками 287–290. ⚠ Эррата 04.09-д («пак НЕ принят») ИСЧЕРПАНА этим актом. **ПАКИ 05.09 ВЫДАНЫ И ИДУТ:** движковый **«денежный стоп перестаёт быть аварией»** (`archive/prompts/BACKEND_MONEYSTOP_SESSION_PROMPT_2026-09-05.md` — строки 271 · 277 · 278 · защёлка отказа) и платформенный **«пустить внутрь можно»** (`archive/prompts/PLATFORM_OPERATIONS_SESSION_PROMPT_2026-09-05.md` — строки 269 бэкапы с предъявленным восстановлением · 270 дверь для не-браузерного клиента · 274 `updateBook` · рантбук деплоя). **ПАКИ 04.09 РАБОТАЛИ ПАРАЛЛЕЛЬНО** (зоны независимы по коду; сцеплений ДВА, и второе найдено 04.09 уже после выдачи промтов — оба про то, чтобы не сорвать платный прогон платформы: > **(1) форма манифеста ЗАМОРОЖЕНА на окно** (`D39.190` п.5): гейт интейка — строгое равенство одной константе, бамп отправил бы каждую книгу в `parser_unavailable`. > **(2) ⚠ ДАННЫЕ ЯЗЫКОВОГО ПАКЕТА — ТОЖЕ.** Правка `backend/internal/lang/data/*.txt` двигает `EmbeddedVersion` → `cutTag` (докстринг `backend/internal/pipeline/manifest.go`: «the embedded data feeds the CJK numerals and sentence terminators that place boundaries») → ключ валидности манифеста → на платформе `recut := storedKey != in.ManifestKey` (`platform/internal/pgstore/readmodel.go`) → `delete from unit_resolutions where book_id`. То есть у книги, за которую заплачено, исчезают замечания читателя и счётчики глав — это строка бэклога **198**. ⇒ **Лендинг правки данных не кладётся, пока книга платного прогона живая**; порядок лендинга — обязанность оркестратора, зоны об этом предупреждены пингами 04.09. Рычаг у бэкенда есть и он объявлен предпочтительным: снять рендер в Go, данные не трогать): бэкенд — вайр-батч `docs/BACKEND_WIREBATCH_SESSION_PROMPT.md`; платформа — «закрыть цикл» `docs/PLATFORM_EXPORT_SESSION_PROMPT.md`. ⚠ Строка **160** взята, но идёт СВОИМ паком ПОСЛЕ двери: она бампает `manifestVersion`, у которого безопасного порядка деплоя нет (`D39.190` п.2). Строка **142** — после шагов 0–1 полигона (`D39.190` п.3). > **Предыдущие паки ОТРАБОТАНЫ 03.09, ПРИНЯТЫ С ДОФИКСОМ и заленджены** — `D39.187` движок, `D39.188` платформа; составы и приёмочные дампы ТЕЛАМИ НОТ, промты в `archive/prompts/` с баннерами исхода, план паков — `archive/reports/NEXT_PACKS_PLAN_2026-09-03.md`, решения — D39.190. ⚠ Живое отсюда одно и оно уже вылечено паком P13: **у формы манифеста БЕЗОПАСНОГО ПОРЯДКА ДЕПЛОЯ НЕТ** — гейт интейка сравнивает версию со строгим равенством одной константе (`platform/internal/ingest/manifest.go`, греп `KnownManifestVersion`), окна двух версий нет, поэтому порядок «сначала платформа, потом движок» из рантбука разворачивается на обратный. ✅ **СНЯТО ЛЕНДИНГОМ 06.09 (`D39.208`): гейта БОЛЬШЕ НЕТ.** Флаг едет в argv на КАЖДОМ спавне и пересчитывается, а названное ниже «живое основание» вылечено расширением условия — `--resnapshot` теперь едет на ЛЮБОМ продолжении, не только после правки банка (`PD-422`). Ниже — прежняя редакция, историей: ⛔ **Проводка `--max-units` в платформу остаётся ГЕЙЧЕНОЙ. Живое основание одно и оно механическое:** единственный писатель `bank_moved_at` — дверь правок банка (`platform/internal/runs/bank.go:211`=`one statement sets it`), а рост АВТО-банка от майнинга этого флага не ставит, поэтому майнящая книга на второй покупке идёт без `--resnapshot` и умирает на снапшот-гарде движка — холд взят, попытка сожжена (`PD-422`). ⚠ **Сюда же переехал остаток закрытой строки 234 (испр. 05.09): проводка полей `rebill_*` через шов — часть ЭТОГО гейта, а не отдельная работа**; ревизия справедливо заметила, что после закрытия 234 её остаток остался без видимого носителя. Это чинится проводкой признака движения банка от майнинга, а не решением владельца. **ОТКРЫТО НА ОРКЕСТРАТОРЕ №22:** ~~**Ресёрч-сессия `textmachine-36`** — лендинг `research/29`~~ **ЗАКРЫТО 04.09.** Оба отчёта топологии заленджены полигоном на СВОЕЙ ветке по прямому указанию владельца (`a7951a7`) и приехали в `main` мержем ветки — то есть маршрутом, который и был назван правильным. Файлы на месте: `docs/research/29-harness-topology-survey.md` и `…-codex.md`. > ⚠ **ЖИВОЙ ОСТАТОК — РЕВЬЮ-ШАПКИ, и он на оркестраторе.** ✅ **У `research/30` шапка НАПИСАНА 05.09 — долг по нему закрыт** (попутно исполнена эррата, которую он сам требовал пять недель: `research/22` «LinguaGacha явно НЕ в мульти-агент/редактор» помечено протухшим; и снято его же требование к `29-codex` — якорь `:368` протух, реальный носитель `:108` говорит слабее и о другом). ✅ **У `29-codex` шапка НАПИСАНА 05.09** — и она подтвердила снятое выше независимо: его же §4 п.12 говорит, что пробел в long-form детекторе машинности — в held-out точности и доле ложных срабатываний, **а не в русском языке**. ✅ **У `research/29` шапка НАПИСАНА 05.09 — ДОЛГ ЗАКРЫТ ПО ВСЕМ ТРЁМ ОТЧЁТАМ.** ⛔ Первым в ней стоит §5.6: **сфабрикованный sha256** (совпали 52 знака из 64, хвост дописан по памяти, потому что хеш ни разу не был виден целиком из-за `cut` в конвейере) — и норма, из него следующая: идентификатор, не виденный ЦЕЛИКОМ в выводе команды, нельзя воспроизводить по памяти. Тот же класс, что `D39.207` п.5, пришедший с другой стороны. ⚠ И граница, которую обязан знать всякий, кто цитирует оттуда числа: из 113 находок автор лично пере-открыла ШЕСТЬ. ⚠ Расхождения `29` и `29-codex` между собой НЕ разрешены никем — автор `29` не читала параллельный отчёт дальше его §1, (⚠ испр. 05.09: сама шапка 29 уже поправлена — «НЕ закоммичено» помечено протухшим, файл в `main` с `a7951a7`; здесь остаётся долг ШАПКИ, а не факта о коммите). До шапок читать оба отчёта как ФАКТУРУ, не как ратифицированное. ⚠ Формулировка, которую шапка обязана нести, иначе следующая сессия выбросит замеры топологии: **судья как СТАДИЯ ДВИЖКА не построен и не вызывался (0 вызовов), но судьи в ПОЛИГОНЕ были и есть.** ⛔ **Маршрут закрыт словом владельца 02.09: «не трогай соседнюю git tree ветку вообще»** — файл принадлежит ветке `polygon`, в `main` приезжает мержем ветки, копированием из соседнего worktree — никогда (№22 так сделал, был поправлен, лендинг откачен). **НОРМЫ, ЗАРАБОТАННЫЕ ЭТИМИ ПРИЁМКАМИ:** - **Зелёная батарея — это ПОЛНЫЙ список пакетов ПЛЮС отсутствие FAIL**, а не отсутствие FAIL: обёртка подавала `exit 0` при падении в хвосте (поймала сама движковая сессия). - **Линтер якорей гоняется ПОСЛЕДНИМ шагом, после того как код замер.** Он судит доки трёх зон, но зоны его не зовут; в этот заход нашёл 21 указатель на исчезнувший код, и правки сдвигали цели дважды подряд — включая мои собственные, уже после починки. - **Якорь разрешается тем, ЧТО он утверждает, а не номером строки, на которой лежал** (движковая сессия записала переезд по совпавшему номеру и промахнулась предметом). - **Колонка «подтверждено» отчёта, пойманного на ложных подтверждениях, снимается с доверия ЦЕЛИКОМ** — критерий, отличавший ошибочные строки от верных, назвать нельзя. - **`pkill` по имени процесса на машине с параллельными сессиями бьёт по чужим.** - **Число или «доказано» уходит владельцу только после СВОЕГО прогона.** ## ⚠ ПИНГ ЗОНЕ БЭКЕНДА (оркестратор №22, 04.09, вечер) — РЕВИЗИЯ ДОКУМЕНТАЦИИ ЗОНЫ ЦЕЛИКОМ Внешний ревизор прочитал `backend/README.md`, все 11 файлов `backend/docs/` (включая оба PUML текстом) и арх-доки движка от первой строки до последней. Правит ЗОНА. Порядок — по цене ошибки. **1. ⛔ `README.md:36` описывает инвариант через ключи, которые загрузка ОТВЕРГАЕТ.** «Канал adult — только permissive (fail-closed)»: `permissive:` и `channel:` — RETIRED и валят конфиг (`internal/config/models.go`, греп `LegacyPermissive`; `internal/config/pipeline.go`, греп `LegacyChannel`). Настоящий механизм — `content_labels` книги × `accepts_labels` модели — в README не назван ВООБЩЕ. Сессия, строящая маршрутизацию контента по README, получит неподнимающийся конфиг. Ту же ложь несут оба PUML. **2. ⛔ ОБА PUML БЕЗ ⚠-БАННЕРА рисуют снесённое**, при том что `docs/README.md` подаёт их как канонические диаграммы, правящиеся «одним коммитом с кодом»: exit-контракт из ЧЕТЫРЁХ кодов (в `cmd/tmctl/main.go` — коды 4, 5 и полоса 10–19), глаголов 6 против 11, `mined_delta`/`mined_rejects` как ключи `book.yaml` (RETIRED, валят загрузку), машинная `.bank-stop.json` (снесена D39.158), `Adult bool`. В заголовке обоих — «синхронизировано с D1–D39.25» при живой голове D39.195. **3. `README.md:95` называет боевой редакторский промпт `v3`** *(⚠ испр. 05.09: второй адрес этого пинга — `10-prompt-architecture.md:23` — снят, потому что этот файл ЗОНА ОРКЕСТРАТОРА и бэкенд его не правит; поправлено своей рукой)* — в `configs/pipeline-c1.yaml` метка `v4-discourse-reflow-nogenre`, и с D39.182 она НЕСУЩАЯ (`TestPromptLabelsPinTheirBytes`). Поверивший README либо бампнет v3→v4 в уже-v4 файле, либо получит красный гейт. **4. `README.md:3` обещает автоматику, которой нет:** «подсистемы не импортируют друг друга (проверяется `go list -deps`)». Сама изоляция ДЕРЖИТСЯ — проверено, — но проверки нет: `grep -rn 'go list' backend --include=*_test.go --include=Makefile` → 0, а `internal/archguard` несёт три анализатора, границы импортов среди них нет. `13-tech-debt-anchors.md` это констатирует, README нет. **5. ⚠ ОБЩНОСТЬ ПЕРЕОЦЕНЕНА, и долг без носителя.** `README.md:23` («гейты по данным, Go-веток по паре нет») и `README.md:16` («`internal/text` — script-agnostic, без языковой политики») — сверх-утверждения: `internal/text/norm.go` встраивает китайскую таблицу трад→упр, складывает катакану в хирагану и БЕЗУСЛОВНО сливает `ё→е` для ЛЮБОЙ цели (белорусская цель ломается тихо); санитайзер считает только `latinLetters`/`cyrLetters`, поэтому греческая/арабская/хинди цель получает «латинскую вставку» на каждом слове; граница слова в банке проверяется только для Latin/Cyrillic. ⇒ Ревью-вопрос «пара, которой в репо нет, без правки Go» для не-кириллической цели отвечается НЕТ, а README это скрывает. **6. Ратифицированная норма зоны держится на СНЯТОЙ строке.** `DISCLOSURE_LAW_DESIGN.md:219-221`: «Пока строка бэклога 246 открыта, новый класс вводится в полосу ТОЛЬКО вместе со сверкой… Закроется 246 — оговорка снимается». 246 ЗАКРЫТА 04.09 (D39.194) ⇒ оговорка снялась молча, и это надо подтвердить или переписать сознательно, а не по факту исчезновения строки. **7. ⚠ СЕМЬ ПРОТУХШИХ ТОКЕН-ЯКОРЕЙ В `backend/docs/` — и до сегодня их не видел никто.** Корень `backend/docs` в линтере ОТСУТСТВОВАЛ с самого его заведения; добавлен 04.09 (`docs/scripts/counts.py`, греп `backend/docs` в `lint_anchors`). ✅ **ЗАКРЫТО 05.09: все семь пере-навешены (`616a8e4` два мёртвых + `e7d6b3f` пять съехавших), `--lint` → 0.** Ниже — состояние на середине дня, читать как историю. ⚠ Прежняя редакция: «починены ДВА из семи, пять живы» (`DISCLOSURE_LAW_DESIGN.md:40-44` целят в `quality.go` · `status.go` ×3 · `bookbuild.go` — зона бэкенда, пинг в её секции). ⚠ Прежняя редакция этой строки говорила «семь пере-навешены» — **ложь, выведенная из ожидания, а не из прогона линта**; поймана внешним ревьюером. Починенные два не съехали, а УМЕРЛИ: целили в (`DISCLOSURE_LAW_DESIGN.md:264` и `MONEY_HONESTY_REPORT.md:285`) не съехали, а УМЕРЛИ: целили в `chunkrun.go`=`SourceEchoExpected: role == roleTerminologist`, подстроки которой на HEAD нет вовсе — её съел переход на `isBankRole`. Прежняя редакция этой строки перечисляла краснеющие цели и была верна ровно до починки. Прежде краснели: `DISCLOSURE_LAW_DESIGN.md:40-44` (пять целей подряд — `quality.go`, `status.go` ×3, `bookbuild.go`), `:264` и `MONEY_HONESTY_REPORT.md:285` (`chunkrun.go:40`). ⚠ Эррата D15.2 от 02.09 УЖЕ указывала мимо — гейт не мог этого увидеть по построению. Команда: `python3 docs/scripts/counts.py --lint`. **8. Ссылки «строка N» на строки, ВЫПАВШИЕ из таблицы при закрытии:** `README.md:26` (103 — фантом, снят 31.08), `pipeline.puml` (99 · 100 · 101 · 125 · 145), `DISCLOSURE_LAW_DESIGN` (246 · 238 · 239 · 194), `internal/membank/decisions.go:84` (210 — закрыта 04.09). Бэклог закрытые строки НЕ хранит, а доки зоны адресуют их как живые. **9. Мелочи с адресом:** `README.md:5` «актуализировано 01.08», тело цитирует ноты 23–28.08 · `13-tech-debt-anchors.md:174` цитирует `STACK.md` в состоянии, которого там уже нет (ручка эффорта `pro` — оба носителя датированы 04.09 и противоречат) · `SEAM_PACK_FINDINGS.md:130` «у `bank-apply` ноль вызывающих на платформе» — `platform/internal/runner/bankapply.go` строит вызов · `:1133` «два хита» → четыре · `MONEY_HONESTY_PLAN-NOTE.md:35` «22 поля» → 21 на её же HEAD. **10. НЕ ОПИСАНО, А НАДО:** пакет `internal/langscreen` (новый, на денежном пути вердиктов) в README не упомянут вовсе · карта пакетов не называет ~20 несущих файлов `internal/pipeline` (`volume.go`, `rebill.go`, `reprice.go`, `refusal.go`, `terminologist.go`, `bookbuild.go`…) и пять в `internal/store` · `cmd/tmmutate` (каталог посадок, объявленный ГЕЙТОМ; ⚠ **число из этой строки снято 06.09 — стояло «141», в дереве 211**: литерал в рабочей строке живёт дольше предмета, поэтому здесь его больше нет — счёт берётся из `cmd/tmmutate/mutations.json`) и `cmd/tmvet` не названы · цена закона раскрытия («загейчен на 40 %», Г1/Г2 не построены) в статус-борде 09 не оговорена. ⚠ **Что оркестратор поправил СВОЕЙ рукой в свою зону тем же заходом:** статус-борд `09-target-architecture.md` говорил «цикл РАЗОМКНУТ» и «канон 0.9.0» в день своего же «освежения» — оба ложны с `adf5e53`/`58bca19`; висячая ссылка на закрытую 246 в шапке секции «Бэкенд»; корень `backend/docs` в линтере. ## Бэклог > ⟶ **ПЕРЕЕХАЛ 06.09 в [BACKLOG.md](BACKLOG.md)** (ратификация — D39.218). Таблица вынесена дословно, **номера строк не менялись**: «строка N» ищется там же, чем и здесь — `grep -n '^| N |' docs/BACKLOG.md`. Заголовок оставлен НАМЕРЕННО, чтобы прежние ссылки «секция „Бэклог“ в PROGRESS» доезжали в один хоп. Счёт очереди — бюллетенем в шапке того файла; **здесь копии НЕТ** (один носитель на факт, D39.112). *(Указатели на архив-слайсы хроники — бюллетенем «Архивы хроники» в CURRENT-STATE; здесь копий нет.)* ## Бэкенд #### Пак «гейт вместо прозы» (07.09, промт `docs/BACKEND_GATES_NOT_PROSE_SESSION_PROMPT.md`, вход HEAD `bd652fd`). НЕ КОММИЧУ — ждёт лендинга **ЗАПИСКА-ПЛАН (§7), написана ДО первой правки.** Пять швов держатся прозой и вырожденными фикстурами; ставлю под каждый гейт, боевой код трогаю ровно в одном месте (§4.2а — единственная заказанная смена поведения). **Порядок и довод порядка.** (1) §4.1 шов заголовка — самый определённый и самый дорогой по последствиям (под M2 книга выходит с «1», «2» вместо названий глав), и его фикстура нужна раньше остальных, потому что на ней же стоит §4.4. (2) §4.2 порядок предвычисления — три части одной работы, и (в) гейт каталога обязан подхватить записи из (1) и (б). (3) §4.4 два теста ингест↔чанкер — тот же пакет `chunk`, что и (1). (4) §4.3 линт словаря классификатора. (5) §4.5 армы — последний, потому что он один умеет сдвинуть байты меток промтов, и его последствия видны только на полной батарее. (6) §4.6 попутные — по факту открытых файлов. **Что считаю рискованным в этом паке — поимённо, до работы.** - **§4.2(а) снапшот-нейтральность.** Единственное место, где пак может нарушить обещание §1. Форма аддитивная (отдельная секция сайдкара, глоссарий не трогается), доказательство — байт-равенство снапшота обеих волн до и после; неравенство = стоп и пинг, а не «зато артефакт непустой». - **§4.1 невырожденность моей же новой фикстуры.** Тот дефект, который пак чинит, — типовое место, где прячется второе вырождение. Мерило задано промтом: **≥2 edit-юнита в главе**, иначе M1 тождественен боевому коду и переживёт новый тест. Числа печатаю оба (чанков на главу и юнитов на главу) и утверждаю их В ТЕСТЕ, чтобы будущая смена бюджета роняла тест, а не тихо вырождала его. - **§4.5 сдвиг меток промтов.** Пере-снятый арм почти наверняка двинет байты `testdata/prompt-labels.json`. Сначала смотрю, ЧТО сдвинулось и следствие ли это заказанной правки, и только потом обновляю леджер; обновление объявляю отдельным пунктом отчёта. - **§4.2(в) пять способов получить зелёный гейт, ничего не проверивший** (список в промте). Мой ответ на каждый — в отчёте по этому пункту. **Замер входа, снятый МНОЙ, а не унаследованный.** Дерево на входе чисто: `git status --short` — 0 строк при HEAD `bd652fd` (контроль: тот же вызов минутой раньше, на HEAD `d3eb56b`, печатал 2 строки — модифицированный `docs/CHAPTER_STRUCTURE_DESIGN_SESSION_PROMPT.md` и неотслеживаемый файл моего промта; оба уехали в `bd652fd`/`d3eb56b`). Копия дерева для мутаций снята в скретчпад, контроль `diff -rq` рабочее↔копия — **0 строк расхождения**. ⚠ Форма копии тогда была `cp -a`; круги 2–4 показали, что она уносит `.env`, и заменили её на `tar` с исключениями — см. круги ниже. **Форма фикстуры §4.1 найдена ЗАМЕРОМ, не подбором.** Пробой на копии (`SegBudget{DraftBudgetOut:1797, EditCeilingOut:3200, FertCJK:1.1978}`) перебраны главы из 2/3/4/5/6 абзацев по 900 рун: 2 абзаца → 2 чанка / **1 юнит**, 3 → 3 чанка / **1 юнит**, 4 → 4 чанка / **2 юнита**, 5 → 5/2, 6 → 6/2. ⇒ порог именно 4 абзаца, и главы из трёх чанков НЕДОСТАТОЧНО: `i == 0` там совпадает с `ChunkIdx == 0`. Беру 4: юнит 0 держит чанки 0–2, юнит 1 — чанк 3, то есть фикстура упражняет ОБА различения сразу — «не-первый чанк внутри того же юнита» и «первый чанк НЕ-первого юнита». **ИТОГ: пять швов, которые держались прозой и вырожденными фикстурами, закрыты гейтами; боевой код тронут ровно в одном заказанном месте (§4.2а), и снапшот-нейтральность этого места доказана байт-равенством, а не формой правки.** Каталог мутаций 211 → 222 записи, из них 11 помечены как подмножество, которое реально ГОНЯЕТСЯ (`make mutations`) — до этого пака зелень каталога означала «посадка на месте», а не «посадка краснит» (строка 313). #### Исход по КАЖДОМУ пункту §4 — пунктов без исхода нет | пункт | исход | чем предъявлено | |---|---|---| | §4.1(а) невырожденные фикстуры | СДЕЛАНО, обе | `chunker_heading_test.go` печатает «8 chunks; chunks per chapter map[1:4 2:4]; edit units per chapter map[1:2 2:2]; chunks carrying a title 2»; `contractblockers_test.go` — «8 chunks in 2 chapters; chapter 1 = 2 units; titles "Глава 1"/"Глава 2"». **Оба числа УТВЕРЖДАЮТСЯ, а не логируются:** `chunksPer[ch] < 2 \|\| unitsPer[ch] < 2` → `t.Fatalf` | | §4.1(а-строгое) ≥2 edit-юнита | СДЕЛАНО | форма фикстуры найдена ЗАМЕРОМ (см. записку-план): 3 абзаца дают 3 чанка / **1 юнит**, 4 абзаца — 4 чанка / **2 юнита**. Взято 4: юнит 0 держит чанки 0–2, юнит 1 — чанк 3 | | §4.1(б) утверждение о не-первом чанке | СДЕЛАНО, с обеих сторон шва | на разрезе — цикл по всем чанкам в `TestSplitChunksHeadingCarried`; на реконструкции — отдельное утверждение в `TestManifestChunksReproduceTheCut`, доказанно НЕ холостое (см. ниже) | | §4.1 M3 (экспорт) | СДЕЛАНО | новый `TestExportCarriesTheChapterTitleOnTheUnitThatOpensTheChapter`: «export: 4 units, leading unit holds 3 chunks, 2 of them carry a title» + утверждение, что `FinalText` начинается заголовком | | §4.1(в) M1·M2·M3·M5 в каталог | СДЕЛАНО, 4 записи | все четыре КРАСНЫЕ, тексты падения в таблице мутаций | | §4.2(а) строка 224 | СДЕЛАНО аддитивно | секция `proposed` в сайдкаре; `TestBankStopPublishesItsProposalsInTheReadOut`; глоссарий не тронут — тест утверждает `total=1 signed=1` (сид) и отсутствие 方源 в `terms` | | §4.2(а) снапшот-нейтральность | ДОКАЗАНА исполнением | `capture.golden` пере-снят на дереве HEAD и на моём: **один и тот же sha256 `c1577859…`, 0 строк расхождения при 252 строках файла**; КОНТРОЛЬ — заведомо сдвинутый `chunkerVersion` даёт 196 строк расхождения и другой `snapshot_draft` | | §4.2(б) мутации порядка | СДЕЛАНО, 2 записи | `bookrun.go` (0 записей из 211 до пака) и `mining.go` — обе красные с адресным текстом | | §4.2(в) подмножество в гейт | СДЕЛАНО, форма выбрана и аргументирована | см. отдельный раздел ниже | | §4.3 линт словаря | СДЕЛАНО | `classifiervocab_test.go` в `internal/pipeline`; печатает «classifier prompts linted: 1; vocabulary asserted: [name place term title female male neuter none]»; отрицательный кейс — В ТЕСТЕ | | §4.3 `bankTypeOK` | СДЕЛАНО | снят; оба места читают `terminology.CandidateTypes`. Контроль: носителей множества в прод-коде осталось **1** (`classify.go:26`) | | §4.4 (A) паритет | СДЕЛАНО | `TestIngestAndChunkerAgreeOnOrdinaryChapterHeaders` — предикаты + сквозной `IngestEncoded`→`SplitChunks` | | §4.4 (B) пин расхождения | СДЕЛАНО, все четыре стороны | `TestIngestAndChunkerDivergeOnAZeroPrologueAndALongHeader`; переворачивается на посаженном БУДУЩЕМ фиксе (предъявлено исполнением) | | §4.5 пере-снятие армов | СДЕЛАНО, 2 арма | не-комментарных строк расхождения арма с c1: было 24/24, стало **3** (ровно блок редактора). Контроль: c1 против себя = 0 | | §4.5 гейт равенства | СДЕЛАНО, форма — структурное сравнение | `config.TestAnArmIsTheProductionConfigWithADifferentEditor`; на ДО-паковом арме краснеет тремя блоками: `Stages`, `Gates`, `Mining` | | §4.5 судьба deepseek-pro | НАЗВАНА: файл СНЯТ | довод и перенос гарантии — раздел ниже | | §4.6 строка 349 (а)(б)(в) | ВЗЯТО | правки на месте | | §4.6 строка 350 | ВЗЯТО: шесть функций РЕШЕНЫ (все шесть — «оставить, причина названа на месте»), инлайн свёрнут | замер вызовов ниже | | §4.7 чего в паке нет | НЕ ДЕЛАЛ | фикс `第零章` не тронут; `chunkerVersion` не двигался (доказано голденом) | ⛔ **ПОПРАВКА К ФОРМУЛИРОВКЕ «единственная заказанная смена поведения — §4.2(а)»: их ДВЕ, и вторая денежная.** Она верна для боевых `c1`/`c2` и НЕВЕРНА для армов. Пере-снятие (§4.5) дало обоим живым армам банковый контур целиком: `prompt_override: ../prompts/zh-ru/translator-banknote.md` с лейблом `v2-reflow-nogenre-banknote`, `mining.contrast_path`, `gates.banknote.enabled: true`, `gates.terminology.enabled: true` с `budget_usd: 1.00` и `classify_budget_usd: 1.00` (`git diff --numstat`: glm **37 вставок / 29 удалений**, mistral **43 / 31** — столбец `--stat` «66» и «74» это их СУММА, а не вставки). ⇒ **прогон по арму теперь ПОКУПАЕТ банковый контур, которого раньше не покупал, и оба его волновых снапшота сдвинуты** (четыре хеша — в круге 2, находка 8). Оплаченных книг это не касается: на арм-файлы репозитория не пиннута ни одна (контроль: 0 строк `pipeline:` на `backend/configs/pipeline-arm-*` при 124 живых ссылках на `backend/configs/`), деплой прибит к боевому. Но это ЗАКАЗАННАЯ строкой 348 смена, а не побочный эффект, и лендинг-нота обязана назвать её отдельно — иначе следующая смена прочтёт «единственная смена — сайдкар» и поставит на этом замер. #### Таблица мутаций — правая колонка это ТЕКСТ падения, а не факт красноты | мутация (id каталога) | где посажена | какой тест покраснел | ТЕКСТ падения | |---|---|---|---| | `TITLE-cut-puts-the-heading-on-the-chapters-first-chunk` (M5) | `chunk/chunker.go` — заголовок на ПОСЛЕДНИЙ чанк главы | `TestSplitChunksHeadingCarried` | «chapter 1 chunk 0 (edit unit 0) heading = "", want "Глава 1"» и «chapter 1 chunk 3 (edit unit 1) heading = "Глава 1", want ""» | | `TITLE-heading-belongs-to-the-chapter-not-the-edit-unit` (M1) | `pipeline/manifest.go` — `ChunkIdx == 0` → `i == 0` | `TestManifestChunksReproduceTheCut`, `TestExportCarriesTheChapterTitle…` | «chunk 3 differs — manifest{chapter 1, chunk 3, unit 1, title "Глава 1"} vs cut{… title ""}» и «exported chapter 1 unit at chunk 3: heading = "Глава 1", want ""» | | `TITLE-manifest-restores-the-heading-at-all` (M2) | `pipeline/manifest.go` — `if false` | те же два | «chunk 0 differs — manifest{… title ""} vs cut{… title "Глава 1"}» и «exported chapter 1 unit at chunk 0: heading = "", want "Глава 1"» | | `TITLE-export-reads-the-units-leader` (M3) | `pipeline/export.go` — `Members[0]` → `Members[len-1]` | `TestExportCarriesTheChapterTitle…` | «exported chapter 1 unit at chunk 0: heading = "", want "Глава 1" — a chapter's title belongs to the unit that OPENS it» | | `ORDER-the-bank-is-published-after-it-is-seeded` | `pipeline/bookrun.go` — `exportBank("run-start/seeded")` ПЕРЕД `seedGlossary` | `TestTheRunStartReadOutAlreadyCarriesTheSeededBank` | «the run-start read-out carries total=0 signed=0, want the seeded row — the bank was published before it was materialised» | | `ORDER-the-stop-holds-its-rows-before-it-publishes-them` | `pipeline/mining.go` — экспорт ПЕРЕД `r.lastBankStopRows = rows` | `TestBankStopPublishesItsProposalsInTheReadOut` | «the read-out published NO proposals while the stop presented 3 — this is the row-224 defect itself» | | `BANKSTOP-proposals-reach-the-read-out` | `pipeline/bankexport.go` — снята публикация секции | тот же | тот же текст | | `HEADING-ingest-and-chunker-answer-the-same-on-an-ordinary-header` | `chunk/ingest.go` — `chapterHeaderMaxRunes` 60 → 6 | `TestIngestAndChunkerAgreeOnOrdinaryChapterHeaders` + 5 прежних | «the ingest cut 2 chapters out of 3 headers» | | `CLASSVOCAB-a-class-the-engine-keeps-must-be-named-in-the-pair-prompt` | `terminology/classify.go` — в `Types` добавлен класс `artifact` | `TestEveryClassifierPromptSpeaksTheEnginesVocabulary` | «../../prompts/zh-ru/classifier.md never names [artifact] where the model can see it» | **Выживших нет: 14 записей, 14 RED, `0 unexpected outcome(s)`, выход 0; гниль якорей всего каталога — `anchors swept: 0 of 225 entr(ies) rotten`.** ⚠ Девять строк таблицы выше — состав на круг 8; пять записей дофикса ниже отдельным блоком, с тем же требованием к правой колонке. **Пять записей ДОФИКСА — тот же формат; тексты сняты `-logs` на копии (5/5 RED, `0 unexpected outcome(s)`, 1m38.4s, `anchors swept: 0 of 225`).** | мутация (id каталога) | где посажена | какой тест покраснел | ТЕКСТ падения | |---|---|---|---| | `TITLE-the-number-in-a-title-is-the-headers-not-the-ordinals` | `pipeline/manifest.go` — заголовок ре-деривируется из ординала: `ch.Heading = "Глава " + strconv.Itoa(...)` | `TestTheBuiltBookCarriesChapterTitlesAndNotTheirNumbers`, `TestManifestChunksReproduceTheCut`, `TestExportCarriesTheChapterTitleOnTheUnitThatOpensTheChapter` | «chunk 4 differs — manifest{chapter 2, chunk 0, unit 2, title "Глава 2"} vs cut{chapter 2, chunk 0, unit 2, title "Глава 3"}». Мутация переживает ЛЮБУЮ фикстуру, где ординал совпадает с номиналом — её ловит только невырожденная (номиналы 1 и 3) | | `TITLE-the-built-book-carries-names-not-numbers` | `pipeline/export.go` — `ce.Heading = ""` | `TestTheBuiltBookCarriesChapterTitlesAndNotTheirNumbers`, `TestExportCarriesTheChapterTitleOnTheUnitThatOpensTheChapter` | «the built book has no chapter titled "Глава 1" — assembleBook substitutes the chapter NUMBER when the export carries none, which is exactly how a book ships as «1», «2»» — тот самый симптом, с которого пак начинался | | `TITLE-the-glued-heading-is-stripped-from-the-body` | `pipeline/bookbuild.go` — снят `strings.TrimPrefix(text, ce.Heading+"\n\n")` | `TestTheBuiltBookCarriesChapterTitlesAndNotTheirNumbers`, `TestAssembleBookMarksEveryHoleKind` | «"Глава 1" appears 2 times in the built book, want 1 — the heading prefix is not being stripped from the body it was glued onto» | | `ARM-an-arm-is-the-production-config-with-a-different-editor` | `configs/pipeline-arm-glm.yaml` — снята строка `cache_ttl: "5m"` | `TestAnArmIsTheProductionConfigWithADifferentEditor/pipeline-arm-glm.yaml` | «pipeline-arm-glm.yaml is not pipeline-c1.yaml with a different editor — Context differs: c1 = {GlossaryInjection:selective GlossaryTokenBudget:800 CacheTTL:5m}, arm = {... CacheTTL:}». ⚠ Первая посадка краснела НЕ ТЕМ механизмом — отказывал загрузчик, до сравнения дело не доходило; пере-сажена на ключ, которого загрузчик не требует | | `BANKSTOP-proposals-belong-to-a-stop-and-to-no-other-boundary` | `pipeline/mining.go` — `r.lastBankStopRows = rows` в ветке авто-продолжения | `TestBankStopDefaultIsAutoContinue` | «the read-out carries 3 proposal(s) after an AUTO-CONTINUE — that section is a signature stop's, and this run did not stop» | Сверх каталога — три посадки, предъявленные исполнением на копиях и НЕ занесённые в каталог (по разным причинам, названным здесь же): 1. **Будущий фикс строки 346** (`parseSectionNumeral`: `v <= 0` → `v < 0`, то есть нулевая секция принимается). Посажен на копии; `TestIngestAndChunkerDivergeOnAZeroPrologueAndALongHeader` покраснел текстом «the prologue now carries the title "Глава 0" — the divergence backlog row 346 pins has CLOSED — that is the fix landing, not a regression. Delete this test and fold the case into TestIngestAndChunkerAgree…», а паритетный тест остался ЗЕЛЁНЫМ. Это и есть контракт пары тестов, предъявленный целиком. В каталог не занесён намеренно: каталог описывает ДЕФЕКТЫ, а это заказанная будущая правка. 2. **Снятие поэлементного сравнения** в `TestManifestChunksReproduceTheCut` (проверка МОЕГО нового утверждения на холостой ход). На копии сравнение убрано, затем посажены M1 и M2 — оба покраснели МОИМ утверждением: «reconstructed chapter 1 chunk 3 (edit unit 1) heading = "Глава 1", want "" — the read path puts a chapter's title on its FIRST chunk only». Утверждение стоит само. 3. **Возврат до-пакового `pipeline-arm-glm.yaml`** из HEAD против нового гейта равенства: три блока названы поимённо — `Stages` (у арма нет `prompt_override` банкнотного переводчика), `Gates` (`Banknote.Enabled:false`, весь `Terminology` нулевой), `Mining` (`ContrastPath:` пуст). #### §4.2(в) — форма гейта каталога: решение и довод **Решение: подмножество живёт СОСЕДНЕЙ целью `make mutations`, а не внутри `battery`.** Довод — числами, а не вкусом: - `make battery` целиком: **2 мин 55 с** (exit 0, `0 issues` линта, 19 `ok` / 0 `FAIL`). - `make mutations` (11 записей): **3 мин 3 с** (exit 0, 11 RED, 0 unexpected, гниль каталога 0). ⚠ Обе цифры — состав ДО дофикса (11 записей). После дофикса состав 14, и пара пере-снята ОДНИМ прогоном каждая: батарея **3 мин 14 с**, мутационная цель **3 мин 59,7 с** — это **123 %**, то есть ВЫШЕ диапазона 87–104 %, который дали девять до-дофиксных пар. Одна пара диапазона не задаёт, но направление однозначно: три новые записи цель удлинили, и решение «соседней целью» дофикс укрепил — внутри `battery` подмножество удвоило бы её время. Довод «внутрь battery» звучит сильно — гейт, который никто не зовёт, воспроизводит дефект строки 313 на шаг выше. Отношение замерено на девяти прогонах и это ДИАПАЗОН, а не одна пара: мутационная цель стоит **87–104 % времени всей батареи** (крайние пары 2:42/3:06 и 3:03/2:55). Брать край как довод нельзя — беру диапазон — то есть внутрь она не «добавилась бы», а почти удвоила бы каждый прогон. Он проигрывает этому и ещё одному факту: **`tmmutate` гоняет пакет БЕЗ `-race`, то есть доказывает МЕНЬШЕ, чем цель `test`, а стоит от неё заметную долю.** Класть внутрь `battery` более слабый по гарантиям прогон ценой такого прироста — плохой размен на цели, которую сессии зовут по десять раз в день. Соседняя цель названа в `Makefile` рядом с `battery`, стоит одной строки в промте следующей смены и не удорожает каждый прогон. ⚠ **Это моё решение, и у него есть цена, которую я называю прямо: соседняя цель может остаться незваной, и тогда дефект строки 313 просто переедет на уровень выше.** Если оркестратор считает, что размен другой, — это правка одной строки: `battery: build vet fmt lint test mutations`. **Пять ловушек §4.2(в) — ответ по каждой:** 1. **Список `-id` руками в Makefile.** Не сделано: состав ВЫВОДИТСЯ из каталога полем `battery` записи (`cmd/tmmutate/main.go`, флаг `-battery`). В `Makefile` слова `-id` нет. Пустое подмножество — не зелень, а отказ: «the catalogue marks no entry `battery`, so the battery subset is empty; a gate with no members proves nothing». 2. **`expect: "survives"` как дверь для подгонки.** Закрыта СТРУКТУРНО, а не дисциплиной: валидатор каталога отказывает на `battery && expect=="survives"` — «an entry with expect "survives" cannot be in the battery subset — it would make the gate green by NOT being caught». Контроль: записей с `battery=true` — **14**, из них `expect=survives` — **0**. 3. **`git archive HEAD` вместо копии рабочего дерева.** Цель копирует РАБОЧЕЕ дерево; иначе гейт судил бы HEAD и моих новых пинов не видел. ⚠ Форма копии сменилась дважды по ходу кругов и сейчас такова: `tar -cf … --exclude=./bin --exclude='./.env*'` с якорем на каталог самого `Makefile`, две команды через `&&` (конвейер терял статус источника), копия в `mktemp -d`, уборка `trap … EXIT INT TERM` — то есть и на падении. Секреты в копию НЕ пишутся вовсе, а не удаляются из неё вторым шагом. 4. **`Package` — пакет ПИНА, а не правки.** Соблюдено и предъявлено двумя записями: `TITLE-cut-puts-the-heading…` правит `internal/chunk` и судится `./internal/chunk/` (пин там же), а `CLASSVOCAB-…` правит `internal/terminology`, но судится `./internal/pipeline/` — потому что каноническая форма промта реализована там. Запись с чужим пакетом честно сказала бы SURVIVED. 5. **Время — СУММА по записям.** Названо числом ниже, в разделе замеров. ⚠ **В первой редакции этого отчёта разбивка была НЕВЕРНА — я написала «8 в pipeline + 1 в chunk», нашёл круг 2: их 8 и 2.** Сегодня записей 10 (`./internal/pipeline/` ≈ 17 с на запись, `./internal/chunk/` ≈ 0.1 с, плюс по одному базлайну на пакет). **«Выживший мутант красит выход» — предъявлено ИСПОЛНЕНИЕМ, а не объявлено.** На копии в подмножество внесена заведомо выживающая запись (правка комментария, которую поймать нечем): `SURVIVED ZZ-SURVIVOR-PROBE`, `1 mutation(s) run, 1 unexpected outcome(s)`, `tmmutate: not what the catalogue records`, **`make: *** [mutations] Error 1`, EXIT=2**. Там же проверена уборка на ПАДАЮЩЕМ пути: каталогов `/tmp/tmp.*` после падения — **0** (контроль: `mktemp -d` создаёт именно такое имя — проверено вызовом), а исходник в копии восстановлен (якорь комментария на месте, 1 вхождение). ⚠ **И вслух, как требует промт:** инструмент гоняет пакет БЕЗ `-race`. Он доказывает «этот пин ловит эту посадку», а не «пакет чист под гонками» — это остаётся за целью `test`. #### §4.5 — судьба `pipeline-arm-deepseek-pro.yaml`: файл СНЯТ, и вот куда уехали его гарантии **Решение: снять.** Довод, и он не «так чище»: после честного пере-снятия арм совпал бы с `pipeline-c1.yaml` целиком — редактор боевого с D39.22 это и есть `deepseek-v4-pro` + `few_shot: false`. Арм существует, чтобы изолировать ОДНУ переменную; этот не изолировал ни одной. Решающий довод — третий, и он про класс, который пак закрывает: пока файл жив, `TestSwapArmConfigs` пиннул редактора БОЕВОГО конфига под именем АРМА, и законный флип интерим-редактора (D39.22 прямо называет выбор интеримом) ронял бы тест, который в тексте падения говорит «арм неверен», когда уехал c1. Это ровно та форма, где правый вердикт приходит по неправой причине. **Куда уехали гарантии, которые держал только этот файл:** | гарантия | где была | где теперь | |---|---|---| | `few_shot: false` у reasoning-редактора | `TestSwapArmConfigs`, ветка `fewShotOff` (пиннула АРМ) | цикл по `pipeline-c1.yaml` + `pipeline-c2.yaml` в том же файле — теперь пиннуты конфиги, которые это РЕАЛЬНО везут | | «арм не пере-вооружает эхо-мину» | арм-строка | остальные два арма, строка не тронута | | «арм == боевой вне редактора» | нигде (шапка обещала, тест не проверял) | новый `TestAnArmIsTheProductionConfigWithADifferentEditor` | | «арм, совпавший с боевым, — не арм» | нигде | тот же гейт: отдельное утверждение, которое краснеет ровно на этом состоянии | Снято **7 упоминаний** файла (счёт по диффу): пять — списки шиппинг-конфигов (`config/echoregen_shipping_test.go` ×1, `config/content_labels_test.go` ×2, `config/prompt_pack_test.go` ×1, `pipeline/promptlabel_test.go` ×1), шестое — строка таблицы `TestSwapArmConfigs`, седьмое — ссылка в комментарии `pipeline-c1.yaml`. Комментарии `pipeline-c1.yaml` и `pipeline-c2.yaml`, ссылавшиеся на «dspro-арм», пере-написаны: иначе в дереве осталось бы имя, которое ни во что не разрешается (класс строки 299). ⚠ **Предсказание промта про сдвиг байтов меток промтов НЕ ПОДТВЕРДИЛОСЬ, и я проверила ПОЧЕМУ, прежде чем что-либо обновлять.** `TestPromptLabelsPinTheirBytes` зелен БЕЗ единого касания `testdata/prompt-labels.json`; леджер в дереве не изменён. Причина механическая: пере-снятый арм действительно получил `prompt_override` банкнотного переводчика, но ключ `zh-ru/translator/v2-reflow-nogenre-banknote` уже claim'ил `pipeline-c1.yaml`, а осиротевший было ключ `zh-ru/translator/v2-reflow-nogenre` claim'ит `pipeline-c2.yaml` (контроль: греп по `configs/*.yaml` даёт ровно одно вхождение этого лейбла — `pipeline-c2.yaml:29`). Множество ключей не изменилось ⇒ обновлять нечего. **Это важно назвать вслух: сторож осиротевших ключей в этом тесте живой и покраснел бы, если бы claim пропал.** Никакого `TM_UPDATE_PROMPT_LABELS=1` я не запускала. #### §4.6 — попутные: что взято и с каким исходом **Строка 349:** - **(а)** `snapshotdiff.go` дописывал оператору причину, которой не проверял («the auto-bank grew between purchases»). Утверждение снято, осталось то, что функция ЗНАЕТ: «that is the BANK, not a config or prompt edit (what changed in it is in the bank's own history)». В комментарии названо, почему: авто-банк, подписанная владельцем строка, правка сида и реджект двигают ОДНО поле, а функция видит хеш против хеша. - **(б)** Протухшие клаузы про «последовательный драйвер» сняты в `snapshot.go` (две) и `wave.go` (две — тот же класс, нашла попутно). Контроль: вхождений «sequential driver/runner» в `backend/internal/**/*.go` было **5** (snapshot.go ×2, wave.go ×3), стало **1**, и то — в новой фразе «the sequential driver this fold was written for no longer exists». ⚠ Заодно ЗАМЕРЕНО и записано в комментарий: у `Runner.snapshotID()` **ноль прод-вызовов** (5 тестовых). Он не удалён — это вне заказа — но читатель больше не примет его за живой путь. - **(в)** `backend/README.md` называл `status.go` read-only проекцией. Поправлено с указанием пути: `Runner.Redrive` → `Store.ResetChunkStages` — единственный деструктивный путь движка. **Строка 350 — шесть функций, исход по КАЖДОЙ, и он у всех шести один: ОСТАВИТЬ, причина названа на месте.** Замер вызовов (не по имени, а по квалифицированному вызову; контроль — `chunk.SplitChunks` = **12** живых вызовов): | функция | вызовов | что найдено | исход | |---|---|---|---| | `obs.SafeGo` | **0** (1 упоминание — комментарий `waverun.go:405` «NOT obs.SafeGo») | намеренный КОНТРАСТ: там recover обязан уронить прогон | оставлена, к определению добавлено, что вызова нет и почему; удаление повесило бы тот комментарий в воздух | | `text.TokenizeCyrillic` | **0** (2 упоминания — `checks/sanitizer.go:21` и `:197`) | образец паттерна value-default, на который дважды ссылаются по имени | оставлена; ⚠ её прежняя дока УТВЕРЖДАЛА «serves callers that are unconditionally Russian», которых ноль — формулировка исправлена | | `CheapGateResult.UnitScaleHard` | **0** | поверхность контракта Р2, ждёт строку 12 — причина уже стояла | оставлена, дописан факт «вызова нет» | | `CheapGateResult.UnitScaleSoft` | **0** | то же | то же | | `Bank.Voices()` | **0** | read-сторона состояния, которое банк и так грузит; потребителя держит строка 13б | оставлена, причина названа на месте | | `Bank.Pairs()` | **0** | то же | то же | **Словарь родов — четвёртый пункт строки 350, и он оказался НЕ про «четыре носителя», а про врущий текст.** Замер: `membank/memseed.go:600` принимает восемь значений — `"" · male · m · female · f · neuter · n · hidden`, — а текст его собственной ошибки (`:618`) говорил «is not one of male|female|neuter|hidden», то есть НЕ называл короткие формы `m`/`f`/`n`, которые принимает. Предъявлено исполнением: `gender="m"` ПРИНЯТ (нарушения нет), а читатель ошибки заключил бы обратное. Лечение — вывести перечень из самой карты (`knownGenderNames()`), а не писать рядом второй копией; после правки сообщение: `gender "Male" is not one of f|female|hidden|m|male|n|neuter (empty means no gender datum)`. Остальные три носителя (`membank/memory.go:957`, `terminology/classify.go:50`, промт) НЕ трогала: `terminology.Genders` — намеренное ПОДМНОЖЕСТВО без `hidden`, и его довод стоит на месте в доке (`hidden` — решение о сюжете, а не наблюдение по контекстам). **Инлайн «последняя стадия».** ⚠ **Строка 350 здесь неточна, и это стоит поправки: «при готовом `finalStageWave()`» — не тот хелпер.** `finalStageWave()` возвращает ВОЛНУ и уже имеет 10 прод-вызовов (контроль: 10 прод + 3 тестовых = 13, как в строке). Дублировалось же ИМЯ последней стадии — `r.Pipeline.Stages[n-1].Name` — и готового хелпера для него НЕ было. Заведён `finalStageName()` рядом с `finalStageWave()`, оба инлайна свёрнуты (`export.go`, `quality.go`). Контроль после правки: вхождений `Stages[n-1].Name` в `internal/pipeline` — **1**, внутри самого хелпера. #### Правки существующих тестов, вызванные ЗАКАЗАННОЙ сменой поведения (`D39.183`) — объявляю поимённо 1. **`TestSwapArmConfigs`** (`internal/config/echo_mine_test.go`). Что изменилось в поведении: пак ЗАКАЗАЛ пере-снятие армов и назвал снятие `pipeline-arm-deepseek-pro.yaml` одним из двух допустимых исходов. Что тест описывал: три поля арма плюс few-shot-политику. Куда уехала гарантия: `few_shot: false` — на боевые c1/c2 (см. таблицу выше); поле `fewShotOff` снято, потому что оба выживших арма несут НЕ-reasoning редактора и оба держат few-shot по дефолту. 2. **Пять списков шиппинг-конфигов** — снята строка снятого файла. Гарантии не терялись: списки перечисляют, ЧТО подметать, и файла больше нет. 3. **`TestManifestChunksReproduceTheCut`** — фикстура заменена (ja→ru русская проза через `\f` → zh→ru книга с настоящими заголовками). Это не «смена поведения», а лечение вырожденности, ЗАКАЗАННОЕ §4.1(а). Заодно текст падения поэлементного сравнения перестал печатать `%+v` целой главы: сравниваются четыре поля, они и названы. Утверждение не ослаблено — сравниваются те же четыре поля. 4. **`TestSplitChunksHeadingCarried`** — та же причина, §4.1(а). #### КРУГ 2 — адверсариальный проход по СВОЕЙ готовой работе: 18 находок, ВСЕ в моей работе, две блокирующие Веер: два опуса, один по новым тестам и фикстурам, второй по боевому коду и шиппинг-конфигам. Оба мерили исполнением на своих копиях дерева; рабочее дерево не трогали. **Ни одна находка не была снята «по чтению» — каждая либо воспроизведена мной, либо закрыта правкой, чья краснота предъявлена посадкой.** **ДВА БЛОКЕРА, оба — дыры в моих же гейтах:** | находка | почему это блокер | что сделано | чем предъявлено | |---|---|---|---| | **Линт словаря читал `tpl.FewShot`, которого модель НЕ ВИДИТ.** Классификатор рендерится `MessagesWithInjection` (`render.go:306-320`), а тот берёт `tpl.System`, НЕ `SystemFor(fewShotOn)`; блок `---FEWSHOT---` на провод этой роли не уходит вообще | Пак, у которого весь английский словарь лежит в few-shot-блоке, проходил мой линт зелёным, а модель видела только японский. Это ровно тот дефект, который тест объявлял пойманным | Линт сведён к `System`+`User`, довод записан у функции. **Добавлен ВТОРОЙ отрицательный кейс в тот же тест** — пак со словарём только в `---FEWSHOT---` | Возврат линта к прежней форме на копии → `--- FAIL … a pack whose vocabulary lives only in ---FEWSHOT--- was reported to be missing only [] of [name place term title …]` | | **Гейт паритета армов сам был СПИСКОМ из двух имён** — при том что его собственная шапка запрещает списки («A list is what drifted») | Новый `configs/pipeline-arm-*.yaml` не проверял НИКТО, включая валидатор загрузчика: ревьюер положил арм без `mining.contrast_path` — ту самую денежную аварию из шапки теста — и батарея осталась зелёной | Армы ОБНАРУЖИВАЮТСЯ `filepath.Glob`, список удалён; пустая выдача — отказ | С подложенным `pipeline-arm-newcomer.yaml`: `arms discovered: 3 […newcomer.yaml]` → `--- FAIL … load …: gates.terminology is enabled but mining.contrast_path is not set` | **Остальные находки первого ревьюера (тесты):** 3. **Гейт паритета изымал ВЕСЬ стейдж редактора** — арм мог разъехаться с боевым по `temperature` и `reasoning` и остаться зелёным, то есть изолировать три переменные, объявляя одну. Изъятие сужено до МОДЕЛИ (`Model`/`ResolvedModel`/`EscalateTo`/`ResolvedHop`/`FewShot`); температура, reasoning, промт и его лейбл теперь СРАВНИВАЮТСЯ. Предъявлено: `temperature: 0.4 → 1.9` в арме → `--- FAIL … Stages differs`. 4. **`load` замыкал ВНЕШНИЙ `t`**, поэтому `Fatalf` из сабтеста валил родителя и следующие армы не проверялись вовсе. `t` передаётся параметром. Предъявлено: при сломанном glm-арме `--- FAIL …/pipeline-arm-glm.yaml` и рядом `--- PASS …/pipeline-arm-mistral.yaml` — второй арм ПРОВЕРЕН. 5. **Экспорт-тест не покрывал `--pairs`** — а это единственный режим, который читает ЖИВОЙ раскрой (`export.go` берёт `r.bookChunks` ради колонки исходника), тогда как обычный режим джойнит МАНИФЕСТ. Мутация только чанкера оставляла обычный экспорт правым. Оба режима теперь утверждаются одним хелпером. Предъявлено: посадка «заголовок на лидера каждого юнита» в чанкере → `export: … 2 of them carry a title` (ЗЕЛЕНО) и следом `export --pairs: chapter 1 unit at chunk 3: heading = "Глава 1", want ""` (КРАСНО). 6. **Осиротевший док-комментарий:** моя вставка приклеилась к описанию `TestExportGlossaryGateWithheld`, и та функция осталась без комментария. Блок возвращён своей функции. 7. **Порядковая вырожденность фикстур заголовка** — номер в шапке совпадал с порядковым номером главы (`一·二·三`), поэтому «заголовок отрендерен из номера в шапке» и «из счётчика глав» были НЕРАЗЛИЧИМЫ. Класс держался только пином расхождения, который однажды удалят по его же инструкции. Паритетный тест (тот, что переживёт фикс) переведён на **непоследовательные номера `第一章 · 第三章 · 第七章`**: теперь глава 2 обязана называться «Глава 3». Предъявлено посадкой «рендерить из счётчика» → `chapter 2 (header "第三章 继续") opens with heading "Глава 2", want "Глава 3" — the title must come from the header's own number, not from the chapter counter`. **Находки второго ревьюера (боевой код и конфиги):** 8. ⛔ **ПЕРЕ-СНЯТИЕ АРМОВ ДВИГАЕТ ОБА ВОЛНОВЫХ СНАПШОТА АРМ-ПРОГОНА, и я этого в отчёте НЕ НАЗВАЛА.** Замерено ревьюером исполнением: `arm-glm` draft `4380cb28…`→`b7151595…`, edit `a6a66f07…`→`e0b66ee7…`; `arm-mistral` draft `4380cb28…`→`b7151595…`, edit `7d9ba0ab…`→`f7a572b6…`; контроль «тот же файл дважды» — moved=false. Механизм: `stageSnap.PromptVersion`/`PromptSHA256` (банкнотный `prompt_override` черновика) и `banknoteSnapshot()` (`nil`→ненулевой) в обеих волнах. **Оба моих прибора смотрели мимо:** голден грузит `testdata/golden/pipeline.yaml`, а сравнение загруженных значений я делала только по c1/c2. Обещание §1 при этом НЕ нарушено — оно про оплаченные книги, а на арм-файлы репозитория не пиннуто ни одной (контроль ревьюера: 0 строк `pipeline:` на `backend/configs/pipeline-arm-*` при 124 живых ссылках на `backend/configs/`; деплой прибит к c1). Но **назвать это обязана была я, а не ревьюер.** Честный противовес, который тоже стоит записи: флип c1→арм стал ДЕШЕВЛЕ — draft-снапшот арма теперь побайтово равен c1, двигается только edit-волна, ради которой арм и существует; до пака флип двигал обе. 9. ⛔ **Пере-снятые армы больше НЕ КОНСТРУИРУЮТСЯ там, где старые работали:** без `configs/mining-contrast.zh.txt` (артефакта нет в git по построению) `NewRunner` падает громко, и без `langpack_root` в `book.yaml` — тоже. Это КОРРЕКТНОЕ следствие: арм стал настоящей копией боевого, а прежняя «работоспособность» держалась ровно на том, что банковый контур в арме отсутствовал. Но мой пинг по `docs/STACK.md` называл только денежную половину и писал «(б) закрыто» — теперь названа и механическая: «флип = один арм-конфиг» неверно ещё и потому, что флип требует развернуть артефакт контраста и дать книге langpack. 10. **`proposed` был обещан прозой в паке «гейт вместо прозы».** Комментарий `bankexport.go` утверждал «Empty at every boundary that is not a stop», и ни один тест этого не проверял; ревьюер посадил две правки (присваивание `lastBankStopRows` в ветке авто-продолжения; изобретение строки на не-стоповой границе) — обе прошли зелёными. **Закрыто двумя утверждениями и записью каталога** `BANKSTOP-proposals-belong-to-a-stop-and-to-no-other-boundary`. Предъявлено: посадка A → `the read-out carries 3 proposal(s) after an AUTO-CONTINUE`; посадка B → `the run-start read-out carries 1 proposal(s)`. Премиса не вырождена: на авто-продолжении печатается `total=2 signed=0 proposed=0`. 11. **Одно слово `origin` — два словаря в одном документе.** `terms[].origin` это ПРОВЕНАНС (`seed|ruby|mined`, платформа переводит в `given|annotated|found`), а моё `proposed[].origin` — КАНАЛ (`mined|banknote|both`). Соседний комментарий того же файла аргументирует ровно против этого. Поле переименовано в **`channel`**, пока его никто не читает. 12. **Висящее имя в файле, который отчёт назвал «единственным носителем»:** `terminology/classify.go:21` ссылался на `pipeline.bankTypeOK`, снятый этим же паком. Ровно класс строки 299, который я объявляла закрытым для снятого арм-файла. Ссылка пере-написана на живой предмет. 13. **Устаревшее число над урезанным списком:** `echoregen_shipping_test.go` говорил «the two boevoy cores and the **three** editor swap-arms» над списком, который тот же пак урезал до двух. Поправлено. 14. **`make mutations` копировал `.env` и удалял его ВТОРЫМ шагом** — окно, в котором ключи лежат на диске вне репозитория, а SIGKILL внутри него trap'ом не покрыт. Копия делается `tar --exclude=./.env`, то есть `.env` не пишется вовсе. Предъявлено: файлов в копии **432** против **433** в источнике, `.env` в копии **0** при **1** в источнике. ⚠ **Вторая половина этого лечения оказалась ЛОЖНОЙ и исправлена кругом 3** — см. первую строку таблицы ниже: `$(CURDIR)` не тот якорь, за который я его выдала. 15. **`pipelineFieldDiffs` паниковал бы на первом неэкспортируемом поле** `config.Pipeline` вместо адресного текста. Добавлен `CanInterface()`. 16. **Число в моём же отчёте не сходилось с каталогом:** я написала «8 записей в `./internal/pipeline/` + 1 в `./internal/chunk/`», а было 7 и 2. Исправлено ниже вместе с пере-снятыми числами. 17. **Пар-специфика в шиппинг-конфигах удвоилась:** `zh-ru`/`.zh.` в армах было 0/0, стало 2/2 (банкнотный `prompt_override` и `contrast_path`). Это неизбежное следствие того, что арм — копия c1, а перекос признаёт сам c1 (строка бэклога 140); ревью-вопрос «заработает ли пара, которой в репо нет» теперь требует пере-указать три файла вместо одного. **Не чиню — это вне заказа, но называю.** 18. **Что ревьюеры проверили и НЕ нашли** (печатаю, потому что «не нашёл» без предмета неотличимо от «не смотрел»): вырожденных фикстур в новых guard'ах нет — ветка `want == ""` реально исполняется, `"" == ""` нигде; холостых утверждений нет — достижимость каждой новой ветки проверена; полей `config.Pipeline`, которые гейт молча пропускает, нет — все 15 экспортируемые; сценария «мутационный гейт зелёный, ничего не проверив» построить не удалось (exit-статус trap'ом не маскируется — dash 1, bash 1; пустое подмножество и `expect:"survives"` отказывают текстом; базлайн-зелень пакета обязательна); секция `proposed` НЕ может оказаться непустой вне стопа внутри процесса — присваивание одно, стоп возвращает ошибку, и все три прочие площадки экспорта исполняются строго до майнинга. **Необъявленное следствие процессной локальности, найденное ревьюером и стоящее записи:** секция `proposed` живёт в файле ровно до следующего запуска движка — тот перепишет сайдкар на `run-start/seeded` уже без неё, а поскольку `MarkStopPresented` уже пометил поверхности, стоп не повторится и взять секцию будет неоткуда. То есть окно чтения у платформы — от стопа до следующего запуска. Это не дефект моей правки (артефакт всегда был проекцией «как сейчас»), но для платформенной половины строки 224 это условие, а не деталь. #### КРУГ 3 — по правкам КРУГА 2: четыре находки, из них одна — регресс от моего же лечения Круг 3 заказан адресно: в этом проекте лечение предыдущего круга регулярно само становится находкой следующего, и именно так и вышло. | находка | что это | что сделано | чем предъявлено | |---|---|---|---| | **⛔ Мой комментарий утверждал починку, которой НЕТ.** Круг 2 закрыл окно с `.env` заменой `cp -a` на `tar --exclude`, и я написала в `Makefile` (и продублировала в этом отчёте), что якорь `$(CURDIR)` закрывает вызов `make -f backend/Makefile` из корня репозитория. **`$(CURDIR)` — это каталог, ИЗ КОТОРОГО ЗАПУЩЕН make, а не каталог Makefile'а.** Пере-снято мной: из корня подставлялось `tar -C "…/textmachine"`, то есть тарился ВЕСЬ репозиторий, а `--exclude=./.env` якорен к вершине архива и мимо `backend/.env` промахивался | **регресс не в коде, а в УТВЕРЖДЕНИИ:** дефект существовал и при `cp -a`, но круг 2 объявил его закрытым | Якорь заменён на каталог самого Makefile'а: `MAKEFILE_DIR := $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST)))))`. Комментарий пере-написан: названы и настоящая причина, и то, что остальная часть рецепта по-прежнему требует `backend/` рабочим каталогом. Снята и вторая неточность — «world-writable filesystem»: `mktemp -d` даёт 0700, и старая форма тоже | `make -f backend/Makefile -n mutations` ИЗ КОРНЯ подставляет `tar -C ".../textmachine/backend"`; интегральный замер с этим якорем: `.env` внутри копии **0** при контроле «`.env` в источнике: 1», файлов **432** | | **Сужение изъятия сделало гейт ЛОЖНО-КРАСНЫМ для законного арма.** `withoutEditorModel` сравнивал `ReasoningMaxTokens`, а `LoadPipeline` ТРЕБУЕТ этот ключ на additive-billing провайдере (xAI) — арм на редакторе `grok-4.3` не мог ни загрузиться без ключа, ни пройти гейт с ним | два правила репозитория против друг друга; дыру внёс круг 2 (круг 1, гасивший всю стадию, её не имел) | `ReasoningMaxTokens` изъят вместе с моделью, с доводом: он не ВЫБРАН, а НАВЯЗАН выбором модели — в отличие от температуры, reasoning и промта, которые остаются сравниваемыми | подложенный `pipeline-arm-grok.yaml`: `arms discovered: 3`, все три **PASS**; КОНТРОЛЬ — `temperature: 0.4→0.7` в том же арме → `FAIL … Stages differs` | | **Непоследовательные номера сделали индексацию `headers[c.Chapter-1]` небезопасной** — тест, написанный ровно на случай «номер поехал», отвечал бы паникой вместо своего сообщения; соседний тест в том же файле объявляет прямо обратное | замечание, но противоречащее собственной норме файла | добавлена проверка границ с адресным текстом | посадка «счётчик глав ушёл за пределы фикстуры» → `the cut produced chapter 7 and the fixture has 3 headers — the chapter counter no longer indexes them` (паники нет) | | **Утверждение «`proposed` пусто на `run-start/seeded`» слабее, чем звучит:** к этой границе майнинг ещё не выполнялся, поэтому НИКАКОЕ пере-упорядочивание внутри стопа его не покраснит | замечание | утверждение оставлено, но его сила названа В КОММЕНТАРИИ: оно ловит проектор, который ИЗОБРЕТАЕТ или переносит строку (это предъявлено посадкой B круга 2), а гейтом от утечки из майнинга работает соседнее — на авто-продолжении | посадка «сайдкар заполняет секцию на каждой границе» → `the run-start read-out carries 1 proposal(s)`; посадка «`lastBankStopRows` до развилки» этот тест НЕ трогает, и так и записано | **Что круг 3 проверил и НЕ нашёл** (печатаю, потому что «регресса нет» без предмета неотличимо от «не смотрел»): линт словаря ничего не потерял — `---FEWSHOT---` нет ни в одном classifier-паке репозитория, а утверждение про провод верно ИМЕННО для классификатора (свёртку `SystemFor` делает только стадийный путь `runner.go`, не эта роль); оба отрицательных кейса линта падают по нужной причине при возврате каждой из двух прежних форм. Оба режима экспорта проверяются РАЗНЫМ кодом — мутация в default-ветке и мутация в pairs-ветке дают разные падения. Утверждение на авто-продолжении не вырождено: `total=2` при `proposed=0`. `origin`→`channel` не оставил старого имени и читателя не имеет. Содержимое tar-копии эквивалентно `cp -a`: имена **491 против 491**, `diff -r --no-dereference` идентично, режимы и типы совпадают на всех 491, расходится только mtime (tar пишет целые секунды). Текст ошибки родов совпадает с картой целиком и на пустом значении не возникает вовсе. Развести арм с боевым и остаться зелёным круг 3 не смог: три мутации (`contrast_path: ""`, температура редактора, переименование блока `mining:`) — все три красные. Полная батарея круга 3 на копии: **exit 0, 23 из 23 пакетов**. #### КРУГ 4 — по правкам КРУГА 3: три находки, и главная — мой обмен одной дыры на другую | находка | что это | что сделано | чем предъявлено | |---|---|---|---| | **⛔ Круг 3 закрыл ГИПОТЕТИЧЕСКОЕ ложное-красное, открыв РЕАЛЬНОЕ ложное-зелёное.** Я изъяла `ReasoningMaxTokens` из сравнения БЕЗУСЛОВНО, а загрузчик требует его УСЛОВНО — `internal/config/pipeline.go:1042-1044`, только когда `providerReasoning(st.Model) == "additive"`. На subset-биллинге ключ необязателен и не проверяется, но он РАЗМЕРЯЕТ смету (`priceprojection.go`, `stagerun.go`) ⇒ арм мог нести буфер, которого нет у боевого, и остаться зелёным | ровно тот класс, который шапка этого же файла называет своей первой дырой: «вторая переменная, которую арм изолирует, не сказав об этом» | Изъятие сделано УСЛОВНЫМ: гасится только там, где другое правило это НАВЯЗЫВАЕТ. Условие читает модель из исходного конфига, а не из уже погашенной копии | (а) `reasoning_max_tokens: 12345` на glm-5 (subset) → `FAIL … Stages differs … ReasoningMaxTokens:12345`; (б) арм на `grok-4.3` с обязательным ключом → `arms discovered: 3`, все три **PASS**. Ложное-зелёное закрыто, ложное-красное не вернулось | | **`$(abspath …)` не разрешает симлинки — дефект круга 2 был в одном симлинке.** Makefile, симлинкнутый из корня репозитория, снова заякорил бы копию на корень: замер круга 4 — **1 `.env`, 2 корневых маркера, 435 файлов** в копии | тихая утечка ключей перед громким падением | `realpath` вместо `abspath` | пять форм вызова (из `backend/`, `-f` из корня, `-C backend`, абсолютный `-f`, **через симлинк на файл**) дают один и тот же якорь `…/textmachine/backend` | | **Якорь захватывался на 68 строк ниже места, где появился бы `include`.** `$(lastword $(MAKEFILE_LIST))` называет этот файл только до первого `include`; с `include` на 13-й строке копия сжималась до **1 файла** (контроль: 432 при верном якоре) | латентно: ключи не текут, но гейт молча перестаёт копировать дерево, ради мутаций которого существует | `THIS_MAKEFILE := $(realpath $(lastword $(MAKEFILE_LIST)))` захватывается ПЕРВЫМ присваиванием файла | директив `include` в файле сегодня **0** (контроль напечатан ревьюером); после правки порядок больше не важен | **Что круг 4 проверил и НЕ нашёл:** проверка границ в `headingparity_test.go` верна и ИСПОЛНЯЕТСЯ (зелёный прогон доходит до `headers[2]` → «Глава 7», то есть верхний край используется, а не только утверждается); все три клейма пере-написанного комментария про `run-start` подтверждены исполнением в обе стороны — посадка «проектор изобретает строку» краснит именно эту строку, а посадки «пере-упорядочивание внутри стопа» и «утечка в авто-ветку» её НЕ трогают и ловятся соседями; `make -n` для `build/vet/fmt/lint/test/battery/battery-stand/tools-check` побайтово равен HEAD-овскому — ни одна другая цель не сдвинулась; из всего, что «навязано выбором модели», сравниваемым остаётся только `LabelModels`, и он пуст (`map[]`) во всех четырёх конфигах. ⚠ **Процессная находка не про код, но про мои же промты ревьюерам:** я давала всем кругам ОДИН и тот же путь копии, а `cp -a src dest` в СУЩЕСТВУЮЩИЙ каталог вкладывает, а не заменяет — у одного ревьюера настоящий `backend/.env` оказался на уровень глубже, чем указывал его же `rm -f`. Он это заметил и убрал. Контроль сейчас: файлов `.env` крупнее 100 байт в скретчпаде — **0** (четыре подставных по 7–27 байт, оставленные пробами). Это ровно то окно `cp -a` + `rm -f`, о котором предупреждает комментарий в `Makefile`, — и я воспроизвела его в собственной оснастке. #### КРУГ 5 — ВОРКФЛОУ-РЕВЬЮ по осям владельца: 38 находок выдержали, 8 сняты скептиками Заказ владельца был шире чеклиста: «не воркэраунды · историю зачем так сделано · индустриальные стандарты Go без велосипедов · комментарии только конкретика · дожать до логического конца и исполнить ЗАДУМКУ — техдолг, который мешает СЕЙЧАС, с учётом планов дальше». Воркфлоу: **семь линз** (задумка · планы перенарезки · Go-стандарты · история и провенанс · воркэраунды · комментарии · необходимость холодного прогона), каждая находка — через **трёх независимых скептиков с разными установками** (по коду · по заказу · по цене). 146 агентов, 38 находок выдержали, 8 снято. **Класс А — ложные утверждения, которые пак ВНЁС или ПЕРЕ-НАБРАЛ. Все исправлены; каждое опровергалось командой в две секунды, в паке, который называется «гейт вместо прозы».** | # | что было ложно | чем опровергнуто | что стало | |---|---|---|---| | A1 | Шапка моего же гейта армов: «платформа берёт плоские $2.00 за банк ⇒ флип на арм выставит счёт за банк, которого никто не майнил» | `priceprojection.go` `bookOnceUSD`: `if !g.Terminology.Enabled \|\| ContrastPath == "" { return 0 }` — до-паковый арм давал **0**, а не $2 | Механизм назван в верную сторону: арм ехал БЕЗ банка, цена книги молча падала, и контур не был ни настроен, ни оплачен. ⚠ Та же ложь ушла моим пингом в `docs/STACK.md` и уже стоит в строке 348 — пинг исправлен | | A2 | `pipeline-c1.yaml`: «лейбл обязан отличаться от конфигов, которые везут ПЛОСКИЙ `translator.md` (c2 **и армы**)» | Клаузу сделало ложной моё же пере-снятие: `grep -n prompt_override configs/pipeline-arm-*.yaml` → оба везут банкнотный вариант под тем же лейблом | Названо, что плоский везёт сегодня только c2 | | A3 | «dspro ×2 дешевле glm» — в `pipeline-arm-glm.yaml` (я пере-набрала при переписывании шапки) и в `pipeline-c1.yaml:95` | `D39.137` п.4, **ЖИВОЕ**: посылка ПЕРЕВЁРНУТА — в ПИК dspro дороже glm ×1.26, офф-пик дешевле лишь ×1.59, замер на 129 реальных edit-вызовах. Пинг полигона с обоими адресами сдан 30.08 | Оба носителя правлены: факт назван, ратификация жильца объявлена открытой, а не пере-решена мной | | A4 | Мой комментарий у `snapshotID()`: «переживает как эталон, с которым тесты сверяют волновые фолды — сумма которых он и есть» | Тестов, зовущих обе функции, ноль; хеши не складываются; клауза противоречит инварианту 12 строками ниже (драфт берёт БАЗОВУЮ версию банка именно чтобы стоп его не двигал) | Сказано честно: test-only, каждый тест пинит по одному входу фолда; заодно поправлен близнец в `snapshot_wave_test.go` («byte-unchanged, TestGolden proves it» — голден его не видит) | | A5 | «126 of the entries drive internal/pipeline» в `Makefile` и `cmd/tmmutate/main.go` | Пак сам добавил записи: `134 из 221` | счёт по каталогу: `pipeline 134` при `total 222`; после правки `grep -c '134 of'` даёт **1** в каждом из двух носителей. ⚠ Дофикс сдвинул число ещё раз (каталог 225, `pipeline` 137) и оба носителя пере-сняты по каталогу: `137 of the 225` | | A6 | Утверждение (4) пина расхождения: «каждая глава после пролога названа на одну ПОЗАДИ СВОЕГО ЗАГОЛОВКА» + текст падения «расхождение ЗАКРЫЛОСЬ, удали тест» | От заголовка глава не отстаёт вовсе (`第一章` → «Глава 1»); отстаёт от ОРДИНАЛА. Хуже: под настоящим регрессом (титул из счётчика) утверждение предлагало удалить тест | Пере-названо: это вопрос АДРЕСАЦИИ главы, а не расхождение 346; текст падения больше не предлагает удаление. Предъявлено: под будущим фиксом первым срабатывает утверждение (2) с верным сообщением | | A7 | `banknote.go`: «а на локальную копию ничто не ссылалось» | Ссылок было две, в той же функции | Комментарий описывает КОД, а не его починку: назван инвариант (`CandidateTypes` шире `Types`, неизвестный класс молча падает в `term`) | | A8 | Шрамы автозамены «a the / the the / pass pass» — **9 в файлах пака** (+1 в открытом ради A4) | `grep -rhoE` по `internal cmd`: было **18** в 9 файлах | В файлах пака теперь **0** (счёт по четырём файлам), во всём движке осталось **8** — ⛔ их НЕ трогала: сплошной проход по корпусу владелец отложил в отдельный заход | **Класс B — механизм, а не проза.** | # | находка | что сделано | чем предъявлено | |---|---|---|---| | **B1 ★** | **Фикстуры на ЧИТАЮЩЕЙ стороне остались вырождены по НОМИНАЛУ:** `第一节`+`第二节` ⇒ номинал == ординал. Мутация «манифест ре-деривирует заголовок из ординала» переживала ВСЮ батарею (19/19 `ok`); на боевой книге под ней уехал бы заголовок у 2084 из 2282 глав. Это моя же недоделанная диспозиция круга 3: класс закрыт в одной фикстуре из трёх | Все три переведены на `第一节`+`第三节`; ожидания привязаны к НОМИНАЛУ через явные `headingFixtureNominals`/`zhFixtureNominals`; заведена запись каталога | `manifest{chapter 2, chunk 0, unit 2, title "Глава 2"} vs cut{… title "Глава 3"}` — мутация теперь красная. Фикстура печатает `titles "Глава 1"/"Глава 3"` при ординалах 1/2 | | **B2** | **Гниль якорей ВСЕГО каталога вычислялась и молча выбрасывалась** под `-battery`: отчётный цикл отсеивал не-выбранные записи ДО печати. 53 из 221 записи бьют в код радиуса перенарезки — после неё зелень опять означала бы «запись существует» | Заведён статический линт живости по всему каталогу (файл читается, тестов не гоняет); гниль печатается и красит выход | Гниль сегодня **0** при 222 записях. КОНТРОЛЬ: подложенная запись с мёртвым якорем, которую `-id` НЕ выбирает, названа поимённо и уронила прогон | | **B3** | **`tar \| tar` выбрасывал статус источника** — конвейер отдаёт статус последнего звена | Две команды через `&&` + промежуточный архив; `--exclude=./bin` | ЧАСТИЧНЫЙ отказ источника: прежняя форма — «цепочка продолжилась ДА, exit=0, 2 файла из 2»; новая — «нет, exit=2». Копия 6.8 МБ вместо 17 | | **B4** | **Политика few-shot жила списком из двух имён**, тогда как гейт паритета находит армы глобом: третий арм один видит, другой нет | Армы находятся глобом и здесь; решение по few-shot ключевано **МОДЕЛЬЮ РЕДАКТОРА**, незнакомый редактор = отказ, а не дефолт | КОНТРОЛЬ: арм на `gemini-3.1-pro-preview` → `whose few-shot decision is not recorded in editorKeepsFewShot` | | **B5** | Дифф гейта печатал **адрес указателя** вместо значения (`Stage.FewShot` — `*bool`) — единственный адрес починки, который видит оператор | Указатели разыменовываются в самом диффере (stdlib, least mechanism) | `FewShot:&false` против `FewShot:` вместо `FewShot:0x1c79f07269e8` | | **B6** | **У цели `make mutations` не было носителя:** `grep -c 'tmmutate' backend/README.md` → 0 при 2 на `make battery` | Четыре строки в `backend/README.md`, включая довод, почему цель НЕ входит в `battery` | тот же прибор после правки: `make mutations` → **1**, `tmmutate` → **1**, контроль `make battery` → **2** | | **B7** | **Ратифицированный критерий дизайн-пака физически неисполним:** `D39.224` п.8(2) требует рефлексивный тест по образцу `TestEveryCutInputMovesTheTag`, а тот рефлексирует по ИМЕНОВАННОМУ типу — тогда как payload снапшота и `stageSnap` были АНОНИМНЫМИ структурами внутри функции. По JSON так не сделать: 3 из 21 ключа `omitempty` и в payload дефолтной книги отсутствуют | Оба подняты в именованные типы пакета — **и только это**: ни таблицы осей, ни гейта, ни одного нового ключа (шаг 1 принадлежит дизайн-паку, `D39.224` п.7) | `TestGoldenDeterminism` зелён против **ЗАКОММИЧЕННОГО** `capture.golden`, sha `c1577859…` не двигался, `git status` по `testdata/` пуст. Чтение сильнее пере-снятия: пере-снятый голден мог бы согласиться сам с собой мимо репозитория | #### Находка → что сделано → ЧЕМ ПРЕДЪЯВЛЕНО (все круги, ни одной открытой) | # | находка | что сделано | чем предъявлено | |---|---|---|---| | 1 | линт словаря читал `tpl.FewShot`, не доходящий до провода классификатора | линт сведён к `System`+`User`; второй отрицательный кейс в тесте | возврат к прежней форме на копии → `FAIL … a pack whose vocabulary lives only in ---FEWSHOT--- was reported to be missing only []` | | 2 | гейт паритета армов сам был списком имён | армы ищутся `filepath.Glob`; пустая выдача — отказ | подложенный `pipeline-arm-newcomer.yaml` → `arms discovered: 3` → `FAIL … mining.contrast_path is not set` | | 3 | гейт изымал ВЕСЬ стейдж редактора | изъятие сужено до модели и следствий модели | `temperature: 0.4→1.9` в арме → `FAIL … Stages differs` | | 4 | `load` замыкал внешний `t`, падение одного арма отменяло следующие | `t` параметром | сломанный glm → `FAIL …/glm` рядом с `PASS …/mistral` | | 5 | экспорт-тест не покрывал `--pairs` (единственный режим по живому раскрою) | оба режима одним хелпером | посадка в чанкере → `export` ЗЕЛЕНО, `export --pairs: chapter 1 unit at chunk 3: heading = "Глава 1", want ""` КРАСНО | | 6 | док-комментарий `TestExportGlossaryGateWithheld` осиротел моей вставкой | блок возвращён своей функции | `sed -n` по файлу: комментарий стоит перед своей `func` | | 7 | номер в шапке == ординал главы во всех фикстурах | паритетный тест переведён на `第一章·第三章·第七章` | посадка «рендерить из счётчика» → `chapter 2 (header "第三章 继续") opens with heading "Глава 2", want "Глава 3"` | | 8 | пере-снятие армов двигает оба снапшота арм-прогона — не было названо | названо отдельным пунктом отчёта с механизмом, ценой и противовесом | четыре хеша замера ревьюера + два контроля; мои приборы (голден, сравнение c1/c2) смотрели мимо — это тоже записано | | 9 | армы больше не конструируются без артефакта контраста и langpack | названо; пинг по `STACK.md` расширен на механическую половину | две разные жёсткие ошибки `NewRunner` на копии | | 10 | «`proposed` пуста вне стопа» держалось прозой | два утверждения (`run-start`, авто-продолжение) + запись каталога | посадка A → `carries 3 proposal(s) after an AUTO-CONTINUE`; посадка B → `run-start read-out carries 1 proposal(s)`; премиса непуста (`total=2`) | | 11 | `origin` означало провенанс и канал в одном документе | поле переименовано в `channel` | греп `"origin"` по `bankexport.go` — только `terms[]`; платформа поле не читает (её аллоулист без него) | | 12 | висящая ссылка на снятый `pipeline.bankTypeOK` | ссылка пере-написана на живой предмет | греп `bankTypeOK` по `backend/` — **0** (контроль: `CandidateTypes` — 8 живых хитов) | | 13 | «the **three** editor swap-arms» над списком из двух | число поправлено | греп по файлу | | 14 | `make mutations` копировал `.env` и удалял вторым шагом | копия делается `tar --exclude=./.env`; ⚠ якорь `$(CURDIR)` из круга 2 оказался неверным и заменён кругом 3 на каталог самого Makefile'а | файлов в копии **432** при **433** в источнике, `.env` в копии **0** при **1**; из КОРНЯ репо после правки круга 3 — тоже **0** | | 15 | `pipelineFieldDiffs` паниковал бы на неэкспортируемом поле | `CanInterface()` | правка формы; сегодня таких полей 0 из 15 (контроль ревьюера) | | 16 | в отчёте «8 pipeline + 1 chunk» вместо 8 и 2 | число пере-снято прибором | `python3` по каталогу: `battery=true` 10 → pipeline 8, chunk 2 | | 17 | пар-специфика в армах 0/0 → 2/2 | НЕ чиню (вне заказа), названо | счёт ревьюера по `zh-ru`/`.zh.` в `configs/pipeline-*.yaml` | | 18 | словарь родов: текст ошибки не называл принимаемые короткие формы | перечень выводится из карты (`knownGenderNames()`) | `gender="m"` ПРИНЯТ при старом тексте «is not one of male\|female\|neuter\|hidden»; новый текст печатает `f\|female\|hidden\|m\|male\|n\|neuter` | #### Пинги в чужие зоны (сама НЕ трогала) 1. **`docs/STACK.md` строка 12** (зона оркестратора). Она говорит «резерв; флип = один арм-конфиг» и БУКВАЛЬНО верна, но теперь неполна в двух местах: (а) арм-файлов стало ДВА, а не три — `pipeline-arm-deepseek-pro.yaml` снят как совпавший с боевым; (б) цена подмены названа строкой 348 и она денежная — платформа берёт за банк плоские $2.00 по c1, и до этого пака арм ехал без `mining.contrast_path`, то есть пользователю выставили бы $2 за банк, которого никто не майнил. После пере-снятия армы контур несут, и денежная половина закрыта. ⚠ **Но круг 2 нашёл ВТОРУЮ половину, которой в моём первом пинге не было, и она механическая:** пере-снятый арм больше НЕ КОНСТРУИРУЕТСЯ без `configs/mining-contrast.zh.txt` (артефакт крупный, в git его нет по построению) и без `langpack_root` в `book.yaml` — `NewRunner` падает громко на обоих. Это корректное следствие (арм стал настоящей копией боевого, а прежняя «работоспособность» держалась ровно на отсутствии банкового контура), но «флип = один арм-конфиг» теперь неверно и по этой причине тоже: флип требует развернуть артефакт контраста и дать книге langpack. Дописка нужна про ОБЕ половины. 2. **`docs/BACKLOG.md`, строка 346** (зона оркестратора) — **фактическая поправка, а не косметика.** Строка говорит: «84-рунный заголовок: ингест `false`, чанкер `ok=true` (контроль на 12 рунах сходится)». Воспроизвела — и СНАЧАЛА НЕ ПОЛУЧИЛА: на строке `第四章` + 81 руна оба предиката дают `false` при ЛЮБОЙ длине. Причина не в длине: после юнита стоял контентный глиф, и оба предиката отвергают такую строку по РАЗНЫМ, но одинаково срабатывающим правилам. Расхождение воспроизводится только с СЕПАРАТОРОМ после юнита (`第四章:…`): 60 рун — оба `true`, 61 руна — ингест `false`, чанкер `ok=true, n=4`. ⇒ строке нужна дописка «с сепаратором после юнита», иначе следующая смена повторит мою ошибку и заключит, что строка врёт. В тесте это уже зафиксировано контрольной парой 60/61 и предупреждением в комментарии. 3. **`docs/BACKLOG.md`, строка 350** (зона оркестратора) — вторая фактическая поправка: «„последняя стадия“ дважды одинаковым инлайном при готовом `finalStageWave()`» называет не тот хелпер. `finalStageWave()` возвращает ВОЛНУ и уже имеет 10 прод-вызовов; дублировалось ИМЯ последней стадии, и хелпера для него не существовало. Я его завела (`finalStageName()`), но строку стоит поправить, чтобы «готовый хелпер» не читался как «работа уже сделана». 4. **`docs/experiments/00-provider-quirks.md`** (зона полигона, читала только). Её строка про Gemini в цепочках эскалации перечисляет адреса «во ВСЕХ арм-конфигах: `pipeline-c1.yaml:129`, `pipeline-arm-glm.yaml:61`, `pipeline-arm-deepseek-pro.yaml:62`, `pipeline-arm-mistral.yaml:61`». Из четырёх адресов один теперь указывает на снятый файл, а два других сдвинулись пере-снятием армов. Сама не трогала — чужая зона; передаю тебе, чтобы дошло до полигона. ⚠ Само УТВЕРЖДЕНИЕ живо: `gemini-3.1-pro-preview` по-прежнему в дефолтной цепочке обоих оставшихся армов и c1 (контроль: греп `gemini-3.1-pro-preview` по `backend/configs/pipeline-*.yaml` — 3 файла из 4: c1, arm-glm, arm-mistral; в c2 его нет). 5. **Платформенная половина строки 224.** Движок теперь публикует предложенное отдельной секцией `proposed` сайдкара `tm-bank-v1`; версия формата НЕ бампалась. Платформа читает по аллоулисту (`platform/internal/ingest/bank.go`, `json.Unmarshal` без `DisallowUnknownFields` — проверено чтением, поле просто игнорируется), так что НИЧЕГО не ломается. Но экран подписи по-прежнему покажет `total 0, signed 0`, пока платформа не научится читать секцию: её `total/signed` считаются по банковым терминам, а предложенные строки в банк не уезжают и уезжать не должны (иначе неподписанное инъектируется законом — D39.104 п.2). ⇒ вторая половина строки 224 — на платформе, и это её решение, не моё. #### §10 — что НЕ удалось · что не проверено · где сомневаюсь 1. **Паритетный тест §4.4(A) не предъявлен мутацией, которую ловит ТОЛЬКО он.** Каталожная запись `HEADING-…` краснит его — но вместе с ним краснеют пять прежних тестов (`TestChapterUnitJaWebnovel`, `TestSplitTextChapters`, `TestTitleRawIsTakenWhereTheCutAllowsIt`, `ingest_encoding_test.go` и др.). То есть я показала, что тест ЖИВОЙ и говорит про свой предмет, но НЕ показала, что он ловит что-то, чего не ловит корпус. Его уникальный вклад — сквозной путь `IngestEncoded`→`SplitChunks` и то, что он остаётся зелёным под будущим фиксом (это предъявлено исполнением). Честная формулировка: **не опровергнуто, но и не доказано**, что он незаменим. 2. **`Runner.snapshotID()` — ноль прод-вызовов.** Замерено и записано в комментарий, но НЕ решено: удалять его или нет — вне заказа этого пака (строка 350 его не называет). Оставляю как находку. 3. **Влияние секции `proposed` на РАЗМЕР сайдкара не мерено.** На фикстуре три строки; на боевом стопе их было 82. Контексты и evidence я в секцию НЕ клала именно из-за размера (они остаются в текстовой стоп-таблице), но верхняя граница на реальной книге не замерена. 4. **Форма секции `proposed` — моё проектное решение, не ратифицированное.** Поля выбраны под экран подписи (src · dst · kind · origin · freq · spread · conf · invented · contradicts · bank_holds · variants). Если платформе нужен другой набор — это правка одного проектора, но лучше решить ДО того, как она начнёт читать. 5. **Не проверяла поведение `make mutations` на грязной копии при параллельной сессии.** Цель снимает `cp -a` рабочего дерева: если в момент копирования другая сессия правит `backend/`, копия окажется полу-состоянием. Инструмент это заметит (он фингерпринтит цели и требует зелёный базлайн), но сообщение будет про базлайн, а не про гонку копирования. 6. **Линт словаря классификатора ловит МЕНЬШЕ, чем звучит, и я это называю, а не подразумеваю.** Он доказывает, что идентификаторы НА ПРОВОДЕ, но не что модели велено ими ОТВЕЧАТЬ. Пак, который глоссирует свои классы двуязычно («人名 (name)») и тут же велит отвечать по-японски, проходит зелёным — ревьюер построил такой пак и предъявил `PASS`. Закрыть это по-настоящему может только отказ движка на off-vocabulary ответе вместо нынешнего «посчитать и выбросить» (`terminologist.go`, `Log.WarnContext`), а это смена поведения ПЛАТНОГО прогона, и она не в заказе этого пака. Ограничение записано в комментарии самого теста, чтобы следующая смена не приняла зелень за гарантию. 7. **Пар-специфика в шиппинг-конфигах удвоилась и НЕ вылечена** (находка 17 круга 2): `zh-ru`/`.zh.` в армах было 0/0, стало 2/2. Это неизбежное следствие того, что арм обязан быть копией боевого, а перекос живёт в самом c1 и признан строкой 140. Чинить его внутри этого пака означало бы трогать c1 — вне заказа. Называю как долг, который пак УВЕЛИЧИЛ. 8. **Снапшот арм-прогона сдвинут, и обнаружила это не я** (находка 8 круга 2). Оба моих прибора смотрели мимо по построению: голден грузит собственный фикстурный конфиг, а сравнение загруженных значений я делала только по c1/c2. Урок конкретный: доказательство «ничего не сдвинулось» обязано перечислять, ЧТО именно прибор покрывает, — иначе оно доказывает про свой предмет, а читается как про весь пак. 9. **Решение по `battery` vs соседняя цель — размен, а не истина** (см. довод числами выше). Это то место пака, где я больше всего готова услышать «сделай наоборот». #### Цена самопроверки — числом, для владельца | круг | форма | агентов | токенов | что нашёл | |---|---|---|---|---| | 1 | моя проверка исполнением по ходу постройки | 0 | — | форма фикстуры (4 абзаца = 2 юнита), граница 60/61 руны с сепаратором, несоответствие строки 350 настоящему хелперу, врущий текст ошибки словаря родов | | 2–4 | веер `Agent`: тесты · боевой код · правки круга 2 · правки круга 3 | **4** | **≈0.70 млн** | **22 дефекта, все в моей работе:** два блокера (линт читал `---FEWSHOT---`, гейт армов сам был списком), изъятие целой стадии, замыкание внешнего `t`, непокрытый `--pairs`, вырожденность по ординалу, **сдвиг снапшота арм-прогона**, окно с `.env`, ложный якорь `$(CURDIR)`, ложное-зелёное `ReasoningMaxTokens` | | 5 | **воркфлоу** по осям владельца: 7 линз × 3 скептика на находку + сводный вердикт | **146** | **≈13.8 млн** | **38 находок выдержали опровержение, 8 сняты скептиками:** весь класс А (8 ложных утверждений, включая перевёрнутый денежный довод и пере-набранную посылку, опровергнутую `D39.137` 15.08) и весь класс B (вырожденность по НОМИНАЛУ с ценой 2084 главы из 2282 · молча выбрасываемая гниль каталога · потеря статуса в конвейере `tar` · политика few-shot списком · адрес указателя вместо значения · цель без носителя · неисполнимый критерий дизайн-пака) | | | **итого** | **150** | **≈14.5 млн** | | **Что веер нашёл СВЕРХ того, что нашла я сама — честно.** Мои собственные проверки хорошо ловили «работает ли гейт» и плохо — два других вопроса. Первый: **правда ли то, что я написала словами.** Восемь ложных утверждений класса А я не нашла ни одним своим кругом. ⚠ **Поправка к моему же первому изложению: я сказала «три из них уехали в канон моими пингами» — это НЕВЕРНО, и я это пере-мерила.** В канон моими пингами не уехало НИ ОДНО: `git show <коммит>:docs/BACKLOG.md | grep -c 'за банк, которого никто не майнил'` даёт **1** на `4d0b68e` — коммите, который САМ И ЗАВЁЛ строку 348, до выдачи мне пака (контроль: та же единица на `d3eb56b` и `bd652fd`, то есть фраза стояла там всё время). Я её не внесла, а УНАСЛЕДОВАЛА и повторила в двух своих местах — в шапке собственного гейта и в пинге отчёта; оба исправлены. Цена ошибки поэтому другая, чем я сказала: не «я испортила канон», а «я трижды повторила чужую ложь, ни разу её не проверив», хотя опровержение стоит одного грепа. Второй: **закрыла ли я то, что мешает.** Вырожденность по номиналу (B1) — моя же недоделанная диспозиция круга 3: я объявила класс закрытым, закрыв его в одной фикстуре из трёх, и «ни одной открытой» в моей же таблице было неправдой. Неисполнимый критерий дизайн-пака (B7) я бы не увидела вовсе — он виден только тому, кто читает ноту и код одновременно. ⚠ **В цену веера входит и авария:** 146 агентов по моей инструкции сняли 123 копии дерева и забили `/tmp` до 98 %, отчего батарея дала `[build failed]` в десяти пакетах. Это моя ошибка оснастки, а не свойство метода: `tar --exclude` вместо `cp -a` даёт копию 6.8 МБ вместо 17, и уборка за собой стоит одной строки. Оба носителя формы уже исправлены — оркестратором в промтах и мной в шапке `cmd/tmmutate/main.go`. #### ⚠ Инцидент оснастки: мой же веер забил `/tmp`, и батарея посыпалась НЕ по коду Воркфлоу-ревью подняло **146 агентов**, каждый по моей инструкции снимал `cp -a backend` в скретчпад — **123 копии дерева, 4.3 ГБ**. `df -h /tmp` → 5.7G из 5.9G (98 %). Батарея немедленно дала `compile: writing output: no space left on device` в `modernc.org/libc` ⇒ **10 пакетов `[build failed]`** плюс два красных теста в пакетах, которых пак не касается. **Ни одна из этих краснот не про код**, и в результаты она не записана: числа ниже сняты после уборки. Класс известен — та же авария стояла предупреждением хоста в канале сессий от 03.09. Убрала только СВОЁ: 123 каталога с копией `backend/` в моём скретчпаде + 35 остаточных агентских каталогов + крупные бинарники проб; `/tmp` → 26 %. ⛔ Каталоги `/tmp/go-build*` НЕ трогала (их два, могут быть чужими) — ровно потому, что прецедент их сноса в канале уже описан. **Три собственные ошибки оснастки, которые я называю, потому что они мои:** 1. Один и тот же путь копии на всех агентов. `cp -a src dest` в СУЩЕСТВУЮЩИЙ каталог вкладывает, а не заменяет — у одного ревьюера настоящий `backend/.env` оказался на уровень глубже, чем указывал его же `rm -f`. Он это заметил и убрал; контроль сейчас: `.env` крупнее 100 байт в скретчпаде — **0** (четыре подставных по 7–27 байт). 2. Ни одному агенту я не велела убирать копию за собой. 3. Копия снималась `cp -a` целиком — 17 МБ вместо 6.8 МБ, которые даёт `tar --exclude=./.env --exclude=./bin` (та самая форма, которую круг 4 заставил меня написать в `Makefile`). Свой же инструмент я применила к цели `make mutations` и не применила к собственной оснастке. #### Чем предъявлено — команды и числа, снятые ПОСЛЕ последней правки **Батарея — ПОЛНЫМ списком пакетов, снята ПОСЛЕ последней правки (дофикс девятнадцати находок приёмки), на здоровом диске и при свободной памяти.** `make battery` → **exit 0, 3m14.3s**; `golangci-lint` — `0 issues`. `ok` — **19**, `FAIL` — **0**, «no test files» — **4** (`cmd/tmmutate`, `cmd/tmvet`, `internal/chunk/chunktest`, `internal/standdata`). Это ровно входной базлайн оркестратора (19/0/4). Пакеты: `cmd/tmctl` 19.5s · `archguard` 27.6 · `bookfile` 1.1 · `checks` 12.6 · `chunk` 1.6 · `config` 1.8 · `lang` 1.1 · `langscreen` 1.0 · `ledger` 1.0 · `llm` 2.2 · `membank` 12.4 · `miner` 1.5 · `obs` 1.0 · **`pipeline` 168.4** · `runevents` 1.0 · `seed` 1.0 · `store` 31.7 · `terminology` 1.1 · `text` 1.1. ⚠ Числа круга 8 (`2m55.1s`, `pipeline` 151.1) были сняты ДО дофикса и заменены здесь целиком; рост пакета — три новых утверждения дофикса плюс фоновая загрузка машины, состав `ok`/`FAIL`/«no test files» не двинулся. Мои пять новых/переписанных тестов пакета `pipeline` стоят **2.9 с** под `-race` (замер `-run` по их именам), то есть в 152 с пакета они не видны. **Скипы ПОИМЁННО (4):** `TestMinerFullBookParity`, `TestCorpusBankKeyConflicts`, `TestHelperEventsRun`, `TestHelperKillLoop` — все четыре стендовые/хелперные, те же, что до пака. ⚠ **После этого замера дерево ещё раз тронуто — двумя КОММЕНТАРИЯМИ** (`Makefile` и `cmd/tmmutate/main.go`: число `135 of 222` пере-снято по каталогу в `137 of the 225` и сведено в одну строку, чтобы перенос не прятал его от грепа). Батарея пере-прогнана ПОСЛЕ них и подтверждает: `make battery` → **exit 0, 3m29.4s**, `0 issues`, 19 `ok` / 0 `FAIL` / 4 «no test files», те же 4 скипа. Разница во времени (3m14 → 3m29, `pipeline` 168 → 182 с) — фоновая загрузка машины, а не правки: состав ни одной строкой не двинулся. **Мутационный гейт.** `make mutations` → **exit 0, 3m59.7s**, «14 mutation(s) run, 0 unexpected outcome(s)», 14 RED, выживших нет; строка `anchors swept: 0 of 225 entr(ies) rotten` печатается ВСЕГДА, то есть гниль якорей **0 при 225 записях** и ноль идёт со знаменателем (и линт теперь считает якоря тем же прибором, что посадка — круг 6); осиротевших каталогов `/tmp/tmp.*` после прогона — **0**. **Отказы гейта — предъявлены ИСПОЛНЕНИЕМ, а не описанием** (на копии дерева): - пустое подмножество (снял `battery` со всех записей подмножества — на момент этой пробы их было 9, после дофикса 14): `tmmutate: the catalogue marks no entry `battery`… a gate with no members proves nothing`, **exit 1**; - `battery` + `expect:"survives"`: `tmmutate: A-lock-arbiter: an entry with expect "survives" cannot be in the battery subset…`, **exit 1**; - `-battery` вместе с `-id`: `tmmutate: -battery and -id are two selections; pass one`, **exit 2**. **Уборка и чистота дерева после мутационного прогона.** Каталогов `/tmp/tmp.*` после `make mutations` — **0**. В рабочем дереве изменённых файлов `backend/` — 32, и среди четырёх файлов, куда сажались мутации, диффом отличается ТОЛЬКО `export.go` — моей же правкой свёртки инлайна (1 вставка / 4 удаления); `manifest.go`, `chunker.go`, `bookrun.go` — 0 строк. Посадок в дереве не осталось. **Снапшот-нейтральность — два независимых замера.** 1. *Голден.* `capture.golden` пере-снят `TM_UPDATE_GOLDEN=1` на дереве HEAD `bd652fd` и на моём: **sha256 `c1577859f434654698b344975529093cc5f6bd732d107a9fff523e0664e34971` у обоих и у закоммиченного файла**, `diff` — 0 строк при 252 строках файла. КОНТРОЛЬ: на третьей копии заведомо сдвинут `chunkerVersion` → 196 строк расхождения и другой `snapshot_draft` (`37e97bf1…` против `3db58425…`). То есть ноль — настоящий. 2. *Шиппинг-конфиги.* Правки комментариев в `pipeline-c1.yaml`/`pipeline-c2.yaml` голден НЕ покрывает (он грузит собственный `testdata/golden/pipeline.yaml`). Замерено отдельно: HEAD-копия каждого файла и рабочая грузятся `LoadPipeline` и сравниваются `reflect.DeepEqual` — **равны обе пары** (c1: 2 стадии, `gates.terminology.enabled=true`; c2: 3 стадии). КОНТРОЛЬ: тот же прибор на c1 против c2 расхождение ВИДИТ (core «C1» vs «C2», стадий 2 vs 3). Механизм, почему иначе быть не могло: в снапшот фолдятся РАЗОБРАННЫЕ значения плюс канонический (со снятыми комментариями) SHA промта — байтов YAML-файла не хеширует ничто (`brief_hash` считается по полям `book.yaml`, `config/book.go:391`). **Дифф `^func Test` — исполнением.** HEAD `bd652fd`: **1257**; дерево: **1265** (+8). Файлов `_test.go`: 204 → **207**. Восемь новых: `TestIngestAndChunkerAgreeOnOrdinaryChapterHeaders`, `TestIngestAndChunkerDivergeOnAZeroPrologueAndALongHeader`, `TestAnArmIsTheProductionConfigWithADifferentEditor`, `TestEveryClassifierPromptSpeaksTheEnginesVocabulary`, `TestTheRunStartReadOutAlreadyCarriesTheSeededBank`, `TestExportCarriesTheChapterTitleOnTheUnitThatOpensTheChapter`, `TestBankStopPublishesItsProposalsInTheReadOut`, `TestTheBuiltBookCarriesChapterTitlesAndNotTheirNumbers` (последний — дофикс, закрывает симптом, с которого пак начинался). Прибор — `comm -13` над отсортированными списками имён из HEAD и из дерева, а не разность двух счётчиков. **Каталог мутаций.** 211 → **225** записей (+14, чистая дописка: `git diff --numstat` даёт `182 0`, ни одной удалённой строки — сериализация каталога воспроизводится `json.dumps(indent=1)` побайтово, это проверено сравнением с оригиналом ДО правки). `battery=true` — **14** (11 в `./internal/pipeline/`, 2 в `./internal/chunk/`, 1 в `./internal/config/` — до дофикса верификатора там было **0**), из них `expect=survives` — **0**. **Армы.** Не-комментарных строк расхождения с `pipeline-c1.yaml`: было glm **24** / mistral **24**, стало **3** и **3** (ровно `model:` и снятая строка `few_shot: false`). КОНТРОЛЬ: c1 против себя — **0**. #### Деньги **Пак $0. Платных вызовов — ноль.** Ни одной генерации, ни одного обращения к провайдеру: все прогоны — `go test` с фейковым `httptest`-провайдером и детерминированные проекции. Ключи не читались, `.env` не открывался ни разу (и удалялся из каждой снятой копии дерева — `find` по скретчпаду даёт 0 файлов `.env` при живом `backend/.env` в рабочем дереве). #### КРУГ 6 — по правкам КРУГА 5: 15 находок, круги НЕ сошлись с первого раза Воркфлоу из 48 агентов, три линзы (исправленные утверждения · механизмы · подъём боевых типов), по два скептика на находку. **Ни одна не ставит под сомнение лендинг** — боевой код, деньги и сам фолд снапшота чисты, подъём проверен независимо и жёстче голдена (третье дерево с механически откаченным подъёмом дало побайтово тот же дамп 72 payload'ов, `sha256` совпал, AST-сверка набора и порядка полей — идентична). Но дефекты в МОИХ ЖЕ правках круга 5 нашлись, и главный — снова повторение собственного класса. | # | находка | что сделано | чем предъявлено | |---|---|---|---| | **⛔ A2** | **Индексация номинала БЕЗ ГРАНИЦЫ в трёх фикстурах** — ровно тот класс, для которого я двумя кругами раньше поставила границу в `headingparity_test.go` и написала в комментарии, что паника вместо сообщения недопустима. Третья глава ⇒ `panic: index out of range`, и вердикт по **135 из 222** записей каталога умирает разом. Третий носитель был прикрыт СЛУЧАЙНО — более ранняя проверка срабатывала первой | Хелпер `zhNominal(t, chapter)` с `t.Fatalf` в pipeline, явная граница в chunk | Укороченная до одной главы таблица: `the cut produced chapter 2 and the fixture declares 1 headers` в ОБОИХ носителях pipeline — сообщение, не паника | | **⛔ A1** | **Мой новый линт считал якоря НЕ ТЕМ ПРИБОРОМ, что посадка:** `catalogueRot` — по чистому телу файла, `one()` — по накопительному `patched`. Запись, чей второй якорь уникален только после первого edit'а, отработала бы RED и всё равно уронила прогон как «гниль». Заряжено на **7 записях из 222** (поимённо: `B-report-mitigations`, `FC1-cell-key`, `FC7-…`, `WB36-…`, `WB43-…`, `WB60-…`, `WB64-…`) | Линт считает по накопительному тексту и per-file, как посадка | `WB60-volume-report-decided-after-reconcile` → `RED`, секции `CATALOGUE ROT` нет | | **⛔ A3** | **Рецепт копии в шапке инструмента буквально НЕ ИСПОЛНЯЛСЯ:** `tar … -C backend .` требует cwd = корень репо, `go run ./cmd/tmmutate` — cwd = `backend/`, `cd` между ними не было. Он же раздавал конвейер `tar \| tar`, который `Makefile` в этом же дереве называет причиной ложного дефекта | Рецепт приведён к форме цели `mutations`: две команды через `&&`, cwd назван явно | Исполнен буквально: **430 файлов, `.env` 0, 6.8 МБ, `go build ./...` в копии проходит** | | **B4** | «134 of 221» неверно в ОБОИХ числах | `135 of 222` в обоих носителях | счёт по каталогу. ⚠ Дофикс сдвинул каталог ещё раз — сегодня в обоих носителях `137 of the 225`, и число сведено в ОДНУ строку в каждом, потому что перенос строки в `Makefile` прятал его от грепа, которым его же и проверяют | | **B5** | «полный прогон — шесть часов» опровергнут собственным замером: инструмент гоняет БЕЗ `-race` (`grep -c '\-race' cmd/tmmutate/main.go` → **0** при контроле **4** в `Makefile`), значит ~16 с на запись, ≈40 мин, а 6 ч — это та же арифметика по цене батареи с `-race` | Число пере-обосновано честно: назван и режим, и то, что 40 минут всё равно не гоняют по правке | грепом по обоим файлам | | **B6** | Шапка `snapshot_wave_test.go` врала о СВОЁМ ЖЕ файле: «эти тесты тоже зовут `snapshotID()`» — в файле **ноль** таких вызовов | Сказано, где живут его четыре вызывающих | грепом | | **B7** | Шапка `stageSnap` занижала собственный довод вчетверо: «three of its slots are omitempty» — у `stageSnap` **12 из 19**, число 3 принадлежит `snapshotPayload` (21 ключ) | Оба числа названы своими типами | счёт по телам типов | | **B8** | **`TestSwapArmConfigs` перестал пинить, какой редактор в каком арм-ФАЙЛЕ** — глоб плюс ключевание моделью оставили имя файла, единственную ручку выбора арма под деплой, без сторожа | Слаг выводится из `pipeline-arm-.yaml` и обязан входить в модель редактора — из ИМЕНИ, а не списком | КОНТРОЛЬ: подмена редактора mistral-арма на `glm-5` (раньше проходила) → `resolves editor "glm-5", which does not carry the file's own slug "mistral"` | | **C** | Пять мелочей: «по одному входу каждый» при вызывающем, пинящем два · README не называл гниль каталога вторым поводом ненулевого выхода · маска `./.env` против `./.env*` в двух носителях одного правила · у подъёма нет потребителя и носитель обязательства не назван в коде | Все пять дописаны/выровнены | грепом по обоим носителям маски | **B9 — пинг оркестратору, не моя зона.** Ратифицированный якорь `D39.224` п.8(1) адресует ключи снапшота ДИАПАЗОНОМ СТРОК (`snapshot.go:342-425`). Диапазон протух: счёт по нему даёт 21 и в HEAD, и в дереве, но НАБОР другой — в него попали 6 ключей `stageSnap` и выпали 6 ключей payload. ⚠ И честная оговорка: нота говорит «**22** ключа, счёт мой», то есть её счёт не сходился с HEAD (21) ещё ДО моего подъёма — сверка по числу не поймает, она даст третье число. Настоящие адреса после подъёма: `snapshotPayload` — 21 ключ, `stageSnap` — 19. Рекомендация: адресовать ИМЕНЕМ типа, а не диапазоном строк, — теперь это возможно. #### КРУГ 7 — по правкам КРУГА 6: **лендинг ДА, блокеров 0**; две находки уровня «механизм врёт», обе — в инструменте, не в движке Воркфлоу из 29 агентов, две линзы (починки круга 6 · что мешает лендингу), по два скептика на находку. **Ни одна находка не лежит в боевом Go.** Круг 2 внёс ложный якорь, круг 3 — ложное-зелёное, круг 5 — паникующую индексацию; круг 6 регресса в движок не внёс ни одного. Плотность дефектов уехала из движка в отчётность инструмента о себе — это признак близкой сходимости, а не сходимость. | # | находка | что сделано | чем предъявлено | |---|---|---|---| | **⛔ 1** | **Мой новый подметатель гнили ВРАЛ ЧИСЛОМ.** Сентинел `bodies[path] = ""` служил и «нечитаем», и «пустой файл», а `if body == "" { continue }` глотал все последующие записи по тому же пути. На пустом корне шапка печатала «**47 of 222**», тогда как мертвы были все 222 — 175 сгнивших записей читались как живые. Обратный перекос там же: одна запись с двумя мёртвыми якорями давала «2 of 1 entr(ies)» | Отдельный `unreadable map[string]bool` вместо перегруженной пустой строки; шапка считает по УНИКАЛЬНЫМ записям, а не по сообщениям | вызов настоящей функции в изолированном тесте: пустой корень → «сообщений 231, записей **222**, шапка напечатает 222 of 222»; живое дерево → «сообщений 0, записей 0» при контроле «записей в каталоге 222» | | **⛔ 2** | **Рецепт копии в шапке инструмента утекал `.env`, и лечили ровно этот якорь этажом ниже.** `Makefile` получил `-C "$(MAKEFILE_DIR)"` с замеренным доводом, а шапка осталась с голым `tar … .` под комментарием «# from backend/». Замер на фикстуре: теми же флагами на каталог выше — `.env members = 2` при контроле `total members = 9`, в архиве `./backend/.env` и `./backend/.env.example` | В рецепт добавлен ИСПОЛНЯЕМЫЙ страж `[ -f go.mod ] \|\| { echo "run this from backend/"; exit 1; }` и сказано, почему он не декорация | из `backend/`: 430 файлов, `.env` **0**; из корня репо страж срабатывает (`go.mod` там нет) | | 3 | Новый фикстурный хелпер `zhBookWithChapterHeadings` делал `strings.Replace("source_lang: ja", …)` БЕЗ стража — молча вернул бы вход и скормил бы двум тестам ja→ru книгу без langpack, где все сравнения заголовков снова `"" == ""`. Дом уже носит защищённую форму того же в двух других файлах | Добавлена проверка предпосылки с текстом «premise broken» | форма приведена к существующей в `classifyinput_test.go` и `contourpreflight_test.go` | | 4 | Довод «counting each against the pristine body would report **seven** entries as rot» не воспроизводится: обе схемы на живом каталоге дают 0. Семь — это счёт записей В ЗОНЕ РИСКА, поданный как измеренное следствие | Довод переписан на то, что правда: сегодня схема не нужна ни одной записи, семь — риск, а не промах | замер обеих схем | | 5 | `snapshot.go`: «12 из 19 слотов omitempty **и отсутствуют в payload дефолтной книги»** — арифметика верна, «отсутствуют» нет: на голдене стадия `draft` несёт 3 из этих 12 | Сказано, что именно зависит от книги, и названы 3 из 12 на голдене | счёт по голдену | | 6 | Шапка `golden_test.go` пиннула «the snapshotID + payload», хотя файл зовёт только `snapshotIDForWave` — третий носитель той же поправки | Названы волновые фолды и то, что книжно-глобальный здесь НЕ пиннут | грепом: `.snapshotID()` — 5 вызовов, все в других `_test.go` | | 7 | `README.md`: «ДВА повода для ненулевого выхода» не исчерпывающе — их семь | Перечислены все | по адресам `main.go` | | **⛔ 8** | **«Единственная заказанная смена поведения — §4.2(а)» верно для `c1`/`c2` и НЕВЕРНО для армов.** Пере-снятие дало обоим армам банковый контур: прогон по арму теперь ПОКУПАЕТ то, чего не покупал | Вторая смена поведения названа отдельным блоком в исходе по §4 — с ключами, с диффом и с ценой | `git diff --numstat`: glm 37/29, mistral 43/31; ключей контура в каждом — 5 | **Что круг 7 проверил и НЕ нашёл:** ни одного дефекта в боевом Go; границы круга 6 дают сообщение, а не панику; армовый гейт краснеет на трёх мутациях; мутационная батарея дважды «11 mutation(s) run, 0 unexpected»; голден зелён против закоммиченного файла; загруженные `c1`/`c2` HEAD↔дерево равны; на снятый арм-файл не ссылается ничто исполняемое; чужих зон в диффе нет. #### КРУГ 8 — по восьми починкам КРУГА 7: **КРУГИ СОШЛИСЬ на уровне механизма** Воркфлоу из 18 агентов, одна линза, по два скептика на находку. Вердикт: **находок уровня «механизм врёт или ломается» в движке и гейтах проход НЕ дал; блокеров 0; лендингу не мешает ничего.** Осталось восемь правок уровня строки — все закрыты, ниже с предъявлением. | # | находка | что сделано | чем предъявлено | |---|---|---|---| | 1 | **Мой страж рецепта ЗАКРЫВАЛ интерактивный терминал оператора:** `[ -f go.mod ] \|\| { …; return 1 2>/dev/null \|\| exit 1; }` — замер на pty из каталога без `go.mod`: «child still alive after the guard line: **False**» и в bash 5.3.9, и в dash; контроль с заменой стража на `:` — **True** у обоих | Страж стал звеном цепочки: `[ -f go.mod ] && d=$(mktemp -d) && …`, без `exit` вовсе | шелл жив после стража; из `backend/` рецепт даёт 430 файлов и `.env` 0 | | 2 | **Шапка ROT восстанавливала id разбором собственного текста** (префикс до первого `:`). При id с двоеточием счёт врал: замер — «dead entries 4, rot messages 4, header would print **2 of 4**» | `catalogueRot` возвращает пару `(сообщения, число ЗАПИСЕЙ)`, id собираются по ходу | пустой корень → «сообщений 231, **записей 222**» при контроле «в каталоге 222»; запись с id `X:probe` и двумя мёртвыми якорями → «сообщений 2, **записей 1**» | | 3 | **Класс незащищённого `strings.Replace("source_lang: ja", …)` я закрыла в 1 площадке из 6** — уехавший якорь молча даёт ja→ru книгу без лангпака, где сравнения заголовков снова `"" == ""` | Страж «premise broken» добавлен в три оставшиеся | **6 из 6** площадок несут страж (счёт по файлам идиомы) | | 4 | Пример в шапке `-id A-lock,G-byte-gate` при копипасте падал: `no mutation "A-lock" in the catalogue` | `A-lock-arbiter` | обе записи есть в каталоге | | 5 | «A full run is six» — без единицы, и цифра чужая: `Makefile` того же пака её уже поправил | «~40 min без `-race` — режим, в котором гоняет этот инструмент» | оба носителя согласованы | | 6 | `README.md`: перечень поводов ненулевого выхода объявлен исчерпывающим и не полон (не названы переименованный `run`-фильтр, невалидный каталог, пустое подмножество, неизвестный `-id`) | Перечень дополнен, и вместо обещания исчерпывающести дан АДРЕС полного перечня — ветки в исходнике | по адресам `main.go` | | 7 | Три доккомментария слиплись в один над `zhNominal`, а `zhBookWithChapterHeadings` и `mustIngestChapters` остались без описания | Каждый вернулся своей функции | у каждой из трёх свой комментарий | | 8 | В моём же отчёте «glm +66, mistral +74» прочитано как ВСТАВКИ, а это сумма столбца `--stat` | По `--numstat`: glm 37/29, mistral 43/31 | тем же прибором | ⚠ **Поправка к предъявлению круга 7, найденная кругом 8 и принятая:** доказательство «на пустом корне гейт печатает 222 of 222» через `go run … -root <пустой>` НЕ воспроизводится — прогон останавливается раньше на «./internal/pipeline/ is NOT GREEN before any mutation is planted». Суть находки верна и доказана прямым вызовом `catalogueRot` в изолированном тесте (так в отчёте и записано), но САМ СПОСОБ замера, будь он взят из вердикта круга 7 дословно, не сработал бы. Разница между «утверждение верно» и «этой командой оно проверяется» — ровно то, что этот пак и ловит. #### ДОФИКС ПРИЁМКИ — два верификатора оркестратора, 19 находок, ни одной блокирующей Оркестратор честно пометил, что это ЕГО замеры, а не мои, и велел пере-снимать самой. Пере-сняла каждую. **Все подтвердились**, кроме одной (A), которая оказалась уже покрытой моим же дофиксом — и это я тоже сказала числом, а не «наверное». **Верификатор 1 (судил дифф против заказа, отчёт не читал):** | # | находка | пере-снято мной | что сделано | |---|---|---|---| | **F1** | **Линт словаря пинит ОДНО направление и сжимается вместе со своим предметом:** удаление слова из `terminology.Types` снимает и утверждение о нём | выкинула `"title"` из `Types` → **19 ok / 0 FAIL**, не ловит ничто | Страж на вырожденный предел (`len(classifierVocabulary()) == 0`), брат к уже стоявшему «нет `classifier.md` вовсе». ⚠ **Границу называю сама:** общий случай «слово убрали» линт по построению не ловит; настоящий дом — пин самого словаря, которого в репозитории нет (ресёрч: 0 тестов на `terminology.Types`). Заказу это не принадлежало | | **F2** | `{{title}}` удовлетворял слово класса `title` — плейсхолдер подставляется ДО модели | локализовала оба настоящих вхождения, оставив плейсхолдер → тест **ПРОШЁЛ** и числил `title` утверждённым | Плейсхолдеры `{{…}}` снимаются перед поиском: их ИМЕНА — не текст, которым инструктируют модель. Контроль: та же локализация → `never names [title] where the model can see it` | | **F3** | Строки листа подписи могут потерять ВСЕ решающие поля и остаться зелёными | свела проекцию к `{Src,Dst,Freq}` → пакет `ok` | Сверка проекции со СТРОКОЙ СТОПА поле в поле (`Kind`↔`Type`, `Channel`↔`Origin`, `Spread`, `Conf`, `Invented`, и раздельно `Contradicts`/`BankHolds`, как настаивают комментарии самого типа) | | **F7** | «фикс приземлился, сложи тест в паритетный» висело на страже ПРЕДПОСЫЛКИ | адрес прочитан | Страж говорит своё: «изменился предикат заголовка САМОГО ингеста, а расхождение ниже не судилось ни в какую сторону» | | **F4** | Гейт армов обнуляет `ReasoningMaxTokens`, значит арм с абсурдным значением остаётся зелёным | **отклонила доводом с числом** | `providerReasoning` кодом, а не грепом: `additive` — **1 модель** (`grok-4.3`) при контроле `subset` — 7; оба живых арма subset, `rmt=0`. У боевого этого ключа НЕТ и быть не может ⇒ сравнивать не с чем, любая проверка была бы ПОЛИТИКОЙ, придуманной тестом. Правильный дом — смета трат или загрузчик. Вместо неё **изъятия названы в логе прогона**, чтобы зелень не читалась как «сравнено» | | **последний хоп** | Симптом, которым пак ОТКРЫВАЕТСЯ — книга с «1» и «2» вместо названий — рождается в `bookbuild.go` и не назван ни одним из 90 тест-файлов пакета | подтверждено | **Закрыт, и это ДВЕ гарантии, а не одна:** заголовок становится названием главы, и он же снимается с тела, чтобы не задвоиться. Новый тест в `bookbuild_test.go`, обе занесены в каталог. Предъявлено: потеря заголовка → `the built book has no chapter titled "Глава 1" — assembleBook substitutes the chapter NUMBER…`; неснятый префикс → `"Глава 1" appears 2 times in the built book, want 1` | ⚠ **Поправка к моему же контролю:** первый прогон контроля по неснятому префиксу дал ЧУЖОЙ текст — я держала обе посадки в одной копии. Пере-снято на чистой: дамп книги под одной посадкой — `"Тест\n\n\nГлава 1\n\nГлава 1\n\nОТРЕДАКТИРОВАННЫЙ…"`, ровно задвоение. **Верификатор 2 (смотрел вне карты отчёта):** | # | находка | пере-снято мной | что сделано | |---|---|---|---| | **A** | Своп `Kind↔Channel` и `Freq↔Spread` в проекции проходит зелёным; человеческая таблица стопа печатает те же величины, значит JSON и таблица ОДНОГО стопа разошлись бы четырьмя колонками молча | посадила своп → **FAIL**, `the projection lost deciding fields` | **Уже покрыто** дофиксом F3. Отвечено числом, ничего не добавляла | | **B** | Замер утечки ключей в `Makefile` занижен вдвое и умалчивает чужую зону | пере-мерила: сломанная форма — **61023 члена архива, 2 `.env`** (`backend/.env` И **`eval/.env` — ключи полигона**); починенная — 488 и **0** | Числа в комментарии заменены на настоящие, пересечение зоны названо | | **C** | Зелёный гейт не печатал контрольную величину свипа гнили — оператор не отличал чистый свип от несостоявшегося | воспроизведено чтением кода: баннер только при `len(rot) > 0` | Печатается ВСЕГДА: `anchors swept: 0 of 225 entr(ies) rotten`. Это ⛔-норма проекта, которую я цитирую в отчёте и нарушила в своём же инструменте | | **D** | Сгнившая запись считалась дважды: и прогонным циклом, и статическим свипом, а списки склеивались | посадила запись с мёртвым якорем и ВЫБРАЛА её | Два раздельных числа вместо склейки: `1 unexpected outcome(s) [ZZ-DOUBLE-PROBE (rotted)]; 1 rotted entr(ies)` | | **E** | Два моих носителя называли цену гейта в ПРОТИВОПОЛОЖНЫХ направлениях (README «87 %», отчёт «104 %»); контрольные числа подмножества неверны; отчёт трижды учил форме `cp -a`, которую мой же `Makefile` называет опасной | сверено грепом по обоим файлам | Цена названа **диапазоном 87–104 % по девяти прогонам** в обоих носителях — брать край разброса как довод нельзя. Числа подмножества пере-сняты. Утверждения про `cp -a` разведены: где историческое — сказано, что форма сменилась; где описывало ДЕЙСТВУЮЩУЮ цель — исправлено | | **F** | Арм mistral вёз доллары из АРХИВНОГО плана на опровергнутом ценовом базисе, а его сосед в этом же диффе получил ⚠ про пере-пин цен | сверено с шапкой архива и с `models.yaml` | Числа СНЯТЫ, а не пере-процитированы: названы источник, его статус «история дизайна, не действующий план», и что базис опровергнут `D39.137` | | **G** | Строка лога клала рядом вложенное и непересекающееся число — читается как доля от банка | прочитано | `proposed` → `awaiting_signature_outside_the_bank`, с оговоркой у кода, что `approved` ⊂ `terms`, а эта величина с ними не пересекается | | **H** | У гейта равенства армов **не было записи в каталоге**: 0 из 14 в `./internal/config/` | подтверждено счётом по каталогу | Запись заведена. ⚠ **Первая посадка краснела НЕ ТЕМ механизмом** — её ловил загрузчик, а не сравнение; это «правый вердикт по неправой причине», и я пере-посадила на ключ, который загрузчику безразличен (`cache_ttl`). Текст падения теперь: `is not pipeline-c1.yaml with a different editor — Context differs` | **Ссылка на ноту — нашёл он, чиню я.** В теле `D38.4` слово `few_shot` встречается **0** раз; носитель — `D38.5`, и тема стоит в самом его заголовке (3 хита в теле). Пере-проверила своим прибором по архивному слайсу. Исправлено в **семи** строках, которые написал или перенёс этот пак (`pipeline-c1.yaml`, `pipeline-arm-glm.yaml`, `echo_mine_test.go` ×4, `snapshot.go`). ⚠ **Остаток: ещё 6 строк** с той же неверной ссылкой в чужих, не тронутых паком местах (`fewshot_test.go` ×3, `render.go`, `runner.go`, `config/pipeline.go`) — не трогала, сплошной проход по корпусу владелец отложил; называю числом. #### Знаменатель по каждому классу: «закрыт в N носителях из M», а не «закрыт» Столбец заказан оркестратором для приёмки, и повод конкретный: на классе «вырожденность по номиналу» я объявила «ни одной открытой», закрыв его в ОДНОЙ фикстуре из трёх. Ниже — каждый класс с явным знаменателем и с тем, чем знаменатель посчитан. | класс | закрыт | чем посчитан знаменатель | чем предъявлено закрытие | |---|---|---|---| | Вырожденность фикстуры по **ЧАНКАМ/ЮНИТАМ** (глава даёт ≥2 чанка И ≥2 edit-юнита) | **3 из 3** | все фикстуры шва: `chunker_heading_test.go`, `contractblockers_test.go`, `export_test.go` | числа печатаются и УТВЕРЖДАЮТСЯ в каждой; `cut: 8 chunks; chunks per chapter map[1:4 2:4]; edit units per chapter map[1:2 2:2]` | | Вырожденность фикстуры по **НОМИНАЛУ** (номер в заголовке ≠ ординал главы) | **3 из 3** (было 1 из 3 при моём же «ни одной открытой») | те же три носителя | мутация `TITLE-the-number-in-a-title-is-the-headers-not-the-ordinals` → `manifest{… title "Глава 2"} vs cut{… title "Глава 3"}`; фикстуры печатают `titles "Глава 1"/"Глава 3"` при ординалах 1/2 | | Утверждение «не-первый чанк несёт пустой `Heading`» | **3 из 3 сторон шва**: разрез · реконструкция манифеста · экспорт (и на экспорте — **2 из 2 режимов**, `export` и `--pairs`) | `export.go` развилка `pairs → bookChunks()` против `readModelChunks()` | четыре мутанта M1/M2/M3/M5 красные; мутация только чанкера краснит именно `--pairs` | | Списки, перечисляющие армы поимённо | **2 из 7** (гейт паритета и `TestSwapArmConfigs` — глобом; политика few-shot — по МОДЕЛИ редактора) | `grep -rn 'pipeline-arm-' internal/ --include='*_test.go'`: 7 площадок | подложенный третий арм: гейт паритета его находит и роняет, `TestSwapArmConfigs` требует записанного решения по few-shot. ⚠ **Остальные 5 списков НЕ переведены** (`content_labels_test.go` ×2, `echoregen_shipping_test.go`, `prompt_pack_test.go`, `promptlabel_test.go`) — вне заказа, назван долг | | Ложные утверждения в комментариях пака | **8 из 8** найденных | линза «комментарии» + линза «история», по диффу пака | каждое опровергнуто командой, перечислены в круге 5 | | Шрамы автозамены «a the / the the / pass pass» | **10 из 18** — те, что в файлах, которые пак и так открыл | `grep -rnoE` по `internal cmd`: 18 в 9 файлах | ⛔ Остальные **8** НЕ трогала намеренно: сплошной проход по корпусу владелец отложил в отдельный заход | | Гниль якорей каталога | **225 из 225** проверяются статически при каждом прогоне гейта | линт `catalogueRot` обходит весь каталог, не выборку | гниль сегодня 0; КОНТРОЛЬ — подложенная запись с мёртвым якорем, которую `-id` НЕ выбирает, названа и уронила прогон | | Незащищённый `strings.Replace("source_lang: ja", …)` в фикстурах (уехавший якорь молча даёт книгу без лангпака) | **6 из 6** (было 1 из 6 после круга 7, нашёл круг 8) | `grep -c` по площадкам идиомы в `internal/pipeline/*_test.go` | у каждой площадки страж «premise broken»; форма взята у двух, где она уже стояла до пака | | Функции без вызовов (строка 350) | **6 из 6** решены («оставить, причина названа на месте») | квалифицированный греп по каждой; контроль `chunk.SplitChunks` = 12 живых вызовов | у каждой в определении назван факт «вызова нет» и кто её держит | #### ⛔ ЧЕСТНЫЙ ИТОГ ПО ЗАДУМКЕ, а не по чеклисту (заказ владельца 07.09) Мерило владельца — «техдолг, который мешает СЕЙЧАС и требует рефакторинга ПРЯМО СЕЙЧАС, не по заказу, а по необходимости и с учётом планов». Мерить надо по §2.А ресёрча — четыре вещи, тормозящие разработку СЕГОДНЯ. Вот честный счёт: | §2.А | предмет | закрыт паком | |---|---|---| | 1 | **Норма «копить wire-правки одним касанием».** Корень механический: `classifySnapshotMove` знает ОДНО re-pinnable поле (`repin.go:54` `const memoryVersionField`) при 21 ключе payload; всё остальное = `moveOther` = не пере-пиньится ничего | **НЕ ТРОНУТ.** `git status --short backend` не содержит ни `repin.go`, ни `rebill.go` | | 2 | **Лендинг данных заблокирован порядком** (`embedded_version` — один хеш на 8 файлов с тремя радиусами взрыва) | **НЕ ТРОНУТ.** `internal/lang/**` в диффе отсутствует | | 3 | **Порядок предвычисления не пиненный** | Закрыт наполовину: каталог 211→225, гейт построен и вызывается, но сам порядок в `mining.go` не двинут (лечение аддитивное), а гейт стоит СНАРУЖИ `battery` — объявленный размен | | 4 | **Шов заголовка не утверждается ничем** | **ЗАКРЫТ.** Плюс сверх заказа закрыт класс, которого в заказе не было: номинал главы против её ординала | **Это не вина заказа и не оправдание: `D39.224` и §5 ресёрча отдали Д5 дизайн-паку, а Д4 — окну перенарезки, и закрывать их шагом 0 канон прямо ЗАПРЕЩАЕТ.** Но и ответ на вопрос владельца звучит прямо: **пак закрыл шаг 0 добросовестно и оставил корень.** **Корень одним предложением.** У главы сегодня ТРИ разных числа-адреса — плотный ординал (PK `chunk_status`, адрес redrive), номинал заголовка и контентный `chapterID` манифеста, — и пока предикат осей знает одно re-pinnable поле, любая правка кроя, грамматики заголовка или langpack-данных перекупает книгу целиком; отсюда и норма «копить», и запрет лендинга данных, и невозможность починить `第0章` дешевле глобальной перенарезки. **Что из НЕ взятого я проверила на «а не стоило ли сейчас» — и с каким исходом:** | кандидат | вердикт | довод | |---|---|---| | Д2 `ThinksOnWire` → делегация | **НЕ сейчас** | §6 ресёрча прямо запрещает тащить снапшот-нейтральные мелочи в окно перекроя, а носитель (строка 114в) велит брать «при следующем касании файла». Пак `capability.go`/`models.go` не касался — 0 из 31 изменённого пути. Возьмёт тот, кто их откроет | | Д5 предикат осей | **НЕ сейчас** | ратифицированный критерий дизайн-пака; второй исполнитель — ровно то, от чего предостерегает `D39.224` п.7. **НО** его критерий был физически неисполним, и эту блокировку я сняла — см. B7 | | Д4 `EmbeddedVersion` | **НЕ сейчас** | сам ремонт бампает хеш и CUT-тег: отдельным актом платит ту цену, которую отменяет | | Д8 три семантики ординала, `Chapter.ID` | **НЕ сейчас** | шаги 2 и 3 — ОДНА перенарезка, разнести = заплатить дважды | | Фикс `第0章` (346б) | **НЕ сейчас** | меняет ТЕКСТ чанка ⇒ `chunkerVersion` ⇒ обе волны. Замер: `classifySnapshotMove` на сдвинутом чанкере даёт `moveOther` (контроль: сдвиг только `memory_version` → `moveBankOnly`) | | Отказ движка на off-vocabulary ответе классификатора | **НЕ сейчас** | смена поведения ПЛАТНОГО прогона: пак, называющий типы и не называющий родов, сегодня легален; вынужденная правка промта перекупает classify-фазу (байты промта в `RequestHash`). Незаказанная смена = мотив, запрещённый `D39.183`. Строкой бэклога как пред-условие ко второй паре | #### ⛔ ХОЛОДНЫЙ ПРОГОН НА БОЕВЫХ КОНФИГАХ: НЕ НУЖЕН — и сегодня НЕВОЗМОЖЕН **Невозможен:** `ls configs/mining-contrast.zh.txt` → нет такого файла (контроль: файлов в `configs/` — **7**). `gates.terminology` включён в c1 и теперь в обоих армах ⇒ `CheckMiningContrast` отказывает на пред-полёте **до первого платного вызова**. Стенда тоже нет: `backend/example/chapter1-zh.txt` — **641 байт** (один чанк, майнить нечего), `langpack_root` в его `book.yaml` — 0 хитов при 44 строках; книги в `books/` несут пути `/home/ubuntu/**`, которых на этой машине нет. **Не нужен, потому что заменён поимённо — и всё уже исполнено:** | гейт | что доказывает | |---|---| | `TestGoldenDeterminism` зелён против **ЗАКОММИЧЕННОГО** `capture.golden` | 18 записанных провайдерских вызовов, обе строки волнового снапшота, каждый `request_hash`, тела запросов и итоговые тексты — байты не двинулись. Чтение сильнее пере-снятия: пере-снятый голден может согласиться сам с собой мимо репозитория | | `make mutations` | 14 записей, 14 RED, `0 unexpected`, `anchors swept: 0 of 225` — включая обе новые движковые гарантии секции `proposed` и обе гарантии собранной книги | | `config.TestAnArmIsTheProductionConfigWithADifferentEditor` | пере-снятые армы == c1 вне блока редактора, по загруженным значениям целиком | | равенство загруженных `c1`/`c2` HEAD↔дерево | правки в боевых конфигах — только комментарии | **Если владелец всё же хочет живое подтверждение движковой половины — узкая форма, порядок $0.05:** развернуть артефакт контраста (jieba 0.42.1 → `configs/mining-contrast.zh.txt`), НОВЫЙ каталог проекта и новый `book_id` (чужой стенд не мигрировать), затем `tmctl translate --verify-bank --max-units 3 --ceiling-usd 0.10`. Проверка после: секция `proposed` в `.bank.json` непуста, и её длина равна числу **N из ШАПКИ** `.bank-stop.txt`, а не `wc -l` (таблица многострочная на терм). ⚠ Срабатывание `--ceiling-usd` обрывает прогон в ЧЕРНОВОЙ волне, ДО стопа: деньги потрачены, ответа нет — это «замер не состоялся», а не отрицательный результат. **И главное, почему я против прямо сейчас:** прогон ответит ровно на ПОЛОВИНУ вопроса. Вторая половина отвечается за $0 и отвечается «нет»: аллоулист сайдкара платформы знает три ключа, `proposed` среди них нет (`grep -rn 'json:"proposed' platform/` → **0** при 123 json-тегах в `platform/internal/ingest`), декод нестрогий, секция молча выбрасывается. Экран подписи после лендинга покажет ровно то же, что 04.09. **Разрешение на деньги стоит приберечь для окна перенарезки, где двигается адрес главы** — там живой прогон отвечает на вопрос, который $0-гейтом не берётся. #### Вопросы оркестратору 1. **Решение по `make mutations` vs внутрь `battery`** (§4.2в) — размен, а не истина, и он мой. Числа: 2:28 против 3:22, инструмент гоняет пакет БЕЗ `-race`. Если считаешь, что гейт обязан жить внутри — это одна строка в `Makefile`. 2. **Снятие `pipeline-arm-deepseek-pro.yaml`** — исход названный, но необратимый в моей зоне только на словах: файл удалён из дерева, история цела. Если владелец предпочитает «явный алиас с комментарием» — скажи до лендинга, вернуть дешевле, чем потом. 3. **Форма секции `proposed` в сайдкаре** — моё проектное решение (одиннадцать полей, KWIC и evidence НЕ вошли). Платформа её пока не читает; лучше сверить набор полей ДО того, как начнёт. 4. **Дописки в `docs/BACKLOG.md`** — две фактические поправки (строки 346 и 350) и одна дописка в `docs/STACK.md`, см. раздел пингов. Сама не трогала. #### Заявление о завершённости (§13) - **У каждого пункта §4 есть исход** — таблица в начале секции, пунктов без исхода нет. §4.7 соблюдён: фикс `第零章` не тронут, `chunkerVersion` не двигался (доказано голденом против ЗАКОММИЧЕННОГО файла). - **КРУГИ СОШЛИСЬ на уровне механизма.** Восемь кругов: 1 — моя проверка исполнением по ходу; 2–4 — веер `Agent` (тесты · боевой код · правки круга 2 · правки круга 3), 22 находки; 5 — воркфлоу по осям владельца, 38 выдержавших из 46; 6 — по правкам круга 5, 15; 7 — по правкам круга 6, 8 при вердикте «лендить можно, блокеров 0»; 8 — по правкам круга 7: **находок уровня «механизм врёт или ломается» в движке и гейтах НЕТ**, остались восемь строчных, все закрыты. **ВСЕ 83 находки — в моей собственной работе.** Пять раз подряд лечение предыдущего круга само становилось находкой следующего (ложный якорь `$(CURDIR)` · ложное-зелёное `ReasoningMaxTokens` · паникующая индексация · линт, мерящий не тем прибором · страж, закрывающий терминал) — это записано не как курьёз, а как мера того, чего стоит одна правка без проверки исполнением. - **Знаменатели названы по каждому классу** — отдельная таблица. Два класса я объявляла закрытыми, закрыв их в ОДНОМ носителе из шести и из трёх; оба поймала не я. Столбец «закрыт в N из M» заведён именно поэтому. - **Таблица мутаций полная, выживших нет:** 14 записей подмножества, 14 RED, `0 unexpected outcome(s)`, гниль якорей **0 при 225 записях**. Сверх каталога предъявлено исполнением ещё 20+ посадок — каждая с текстом падения. - **Числа сняты ПОСЛЕ последней правки** и на здоровой машине. ⚠ Два прогона в числа НЕ вошли и названы прямо: один упал по `no space left on device` (моя же оснастка забила `/tmp`), другой был убит системой по нехватке памяти. Падение среды — не результат. - **Всё живое — в ДЕРЕВЕ, а не в письме.** То, что сознательно НЕ сделано, стоит в §10 с доводом; то, что вне моей зоны, — в пингах с адресами и контрольными величинами. - **Чужих зон не касалась.** `platform/`, `frontend/`, `eval/`, `books/`, `backend/docs/` — ноль позиций в `git status`; `docs/BACKLOG.md`, `docs/STACK.md`, `docs/experiments/` — только пингами. `docs/PROGRESS.md` — чистая вставка: `git diff --numstat` даёт **502 0**, ни одной удалённой строки (числа кругов, которые дофикс пере-снял, правились ВНУТРИ строк, добавленных этой же сессией и ещё не закоммиченных, — чужой хроники это не касается). **Заявляю дословно формулой §13: «работа завершена, править не планирую».** #### Дерево на момент сдачи Позиций `git status --short backend` — **39** (35 изменённых · 1 удалённая · 3 новых файла), плюс `docs/PROGRESS.md` (эта секция) — **моих 40**. ⚠ `git status` печатает 45: остальные **5 позиций в `docs/`** (`BACKLOG.md`, `STACK.md`, `architecture/14-api-contract/README.md`, `architecture/18-bank-ontology.md`, `product-requirements.md`) — НЕ мои, это незакоммиченная работа оркестратора в его зоне; проверено чтением диффа (`18-bank-ontology.md` подписана «акт лендинга пака «гейт вместо прозы»»). Я их не трогала и не трогаю. Чужих зон (`platform/`, `frontend/`, `eval/`, `backend/docs/`) не касалась ни одним байтом; `docs/BACKLOG.md` и `docs/STACK.md` не трогала — только пингами. **НЕ КОММИЧУ** — дерево передаётся на лендинг. Новые файлы: `internal/chunk/headingparity_test.go`, `internal/config/armparity_test.go`, `internal/pipeline/classifiervocab_test.go`. Удалён: `configs/pipeline-arm-deepseek-pro.yaml`. #### ДОФИКС ПОСЛЕ ЛЕНДИНГА — три находки третьего верификатора (08.09, к акту `D39.225`) Верификатор шёл по операторской правде и вернулся уже после лендинга: девять находок, шесть я закрыла прежним дофиксом, три пережили коммит. Все три пере-мерены МОИМИ руками — это были его утверждения, не мои замеры, — и все три подтвердились. **F7 — арм-шапка снова называла не то, чем отличается, и это ровно тот класс, ради которого пак существовал.** Комментарий обещал «ЕДИНСТВЕННОЕ отличие арма от боевого — эти четыре строки» и перечислял `model` · `prompt_version` · `temperature` · `reasoning`. Замер диффом против `pipeline-c1.yaml` (комментарии сняты, сравниваются ЗНАЧЕНИЯ): отличий **два** — `model` несёт другого редактора, и строки `few_shot: false` у арма НЕТ. Три из четырёх названных ключей боевому по значению равны, а пятое, настоящее отличие шапка не считала — при том что его тут же объясняет следующий комментарий. Гейт равенства это поймать не мог и не должен: он сравнивает конфиги, а не прозу о них. Комментарий пере-написан по диффу в обоих армах; пере-замер после правки печатает ровно две строки расхождения, ровно те, что названы. **F9 — `snapshot.go`: «its four callers» при трёх перечисленных.** Замер: вызовов `\.snapshotID()` — **5**, в **4** файлах (контроль: вызовов `snapshotIDForWave` — 53). Четвёртый файл — `runner_test.go:1687`, тест `TestRunnerSnapshotFoldsClassifierAndLocalTag`, пинит версию классификатора и локальный бэкенд-тег. Теперь в комментарии стоят оба числа и назван четвёртый предмет. **F10 — `make battery` писала `.skips.log` в РАБОЧЕЕ дерево.** Не новая находка: записана 09.08 в `docs/architecture/13-tech-debt-anchors.md`, Б-122, как не-блокер приёмки пака стандартов — месяц пролежала с носителем. Замер: `git check-ignore` → не игнорируется; убирается на обоих штатных путях, переживает Ctrl-C. Закрыто В ИСТОЧНИКЕ, а не `.gitignore`: харвест-лог уехал в `mktemp` с trap — файла в дереве больше нет вовсе, прятать нечего. ⛔ **И собственная проба этой же правки поймала в ней дефект — печатаю, потому что вердикт по цвету от вердикта по тексту отличается только этим.** Первая редакция ставила `trap 'rm -f "$log"' EXIT INT TERM`, как и соседняя цель `mutations`. Проба SIGINT-ом показала: POSIX-шелл ПРОДОЛЖАЕТ прерванную строку после возврата из обработчика, и цепочка доехала до последнего шага с уже удалённым логом — напечатав `(none)`, то есть «скипов нет», по несостоявшемуся сбору. Тихий скип, читающийся как покрытие, — ровно то, что этот проход и заведён ловить. Обработчик `INT`/`TERM` теперь ВЫХОДИТ (`exit 130`), а не только убирает; та же правка внесена в `mutations`, где форма была та же. Предъявлено исполнением: прерванный прогон — вывода нет, `RC=130`, остаточных `/tmp/tmp.*` 0, мусора в дереве 0; КОНТРОЛЬ на штатном пути — та же цепочка печатает строку `--- SKIP` и убирает за собой. **Попутно закрыта соседняя дверь того же класса.** `backend/.gitignore` держал одну строку `/tmctl` — артефакт `go build ./cmd/tmctl/`, запущенного из корня зоны. Пакетов `cmd/` три, и вчерашний `tmmutate` висел в `git status` сороковой позицией сдачи. Внесены все три (`/tmctl` · `/tmvet` · `/tmmutate`); проверено `git check-ignore`: три игнорируются, `internal/pipeline/snapshot.go` — нет, то есть правило не слишком широкое. ⛔ **И ВТОРОЙ дефект в той же правке — его поймал уже гейт, а не проба.** Пере-набирая строку `mutations` под новую форму trap'а, я срезала из неё `mkdir "$tmp/backend"`. `make mutations` упал за 0,02 с текстом `tar: /tmp/tmp.…/backend: Cannot open: No such file or directory` — то есть копия не создавалась вовсе, и гейт отказал ДО первой посадки, а не сделал вид, что прошёл. Восстановлено; числа ниже сняты после восстановления. Две правки подряд в одном рецепте, два дефекта — обе поймало ИСПОЛНЕНИЕ, ни одну не поймало перечитывание. **Якоря каталога после правок целы:** 225 записей проверено, битых якорей 0 (прибор — тот же счёт вхождений `find`, что делает посадка). **Числа, снятые ПОСЛЕ восстановления рецепта, ничем после них дерево не тронуто.** `make mutations` → exit 0, **3m52.6s**, «14 mutation(s) run, 0 unexpected outcome(s)», 14 RED, `anchors swept: 0 of 225 entr(ies) rotten`. Затем `make battery` → exit 0, **3m40.0s**, `0 issues`, `ok` 19 / `FAIL` 0 / «no test files» 4, скипов 4 — те же. Мусора после обоих прогонов: `.skips.log` в дереве **0**, осиротевших `/tmp/tmp.*` **0** (контроль: файлов в корне зоны 17). Записи `ARM-…` в подмножестве это касается прямо — она сажается в `pipeline-arm-glm.yaml`, чью шапку правил F7, и краснеет тем же механизмом, что и до правки. ### Пак «ЗАКОН БАНКА — ЧЕСТНО» (06.09, промт `docs/BACKEND_CONSISTENCY_SESSION_PROMPT.md`, вход HEAD `e4097cb`). НЕ КОММИЧУ — ждёт лендинга **Итог: закон банка описан тем, что код делает, и найдена дыра ШИРЕ заказанной — стадия схлопывания не сверяла свою выработку со строкой банка на тот же ключ ни при какой подписи.** Закрыто в двух местах (схлопывание + страховка на слиянии), репортом, без смены поведения платного прогона. **ШЕСТЬ кругов самопроверки нашли 43 находки В МОЕЙ ЖЕ работе** (18 + 8 + 5 + 6 + 4 + 2); круг 6 сказал «сошлись» — новых находок в коде пака нет. Шесть находок — ложные утверждения в моих же комментариях, то есть ровно тот класс, который пак чинил; две внесены лечением предыдущего круга; один и тот же шов «писатель ↔ читатель» ловился ТРИ круга подряд, после чего был убран целиком, а не подпёрт четвёртой заплатой. Все разобраны, списки ниже. ⚠ **Комментарии этой смены написаны под рекомендацию владельца 06.09** («только важные детали или обоснования, без прозы, воды, истории и странных гарантий»; носитель — `docs/architecture/12-go-style-notes.md` §1, статус РЕКОМЕНДАЦИЯ). Применена только к СВОИМ комментариям пака: сплошного приведения корпуса рекомендация не заказывает. Единственный комментарий вне пака, который я тронула, — `internal/pipeline/export.go` (`TextModified`): моя правка `chunkstatus.go` сделала бы его утверждение рассогласованным, и оставить два живых противоречащих описания одного факта было нельзя. ⚠ **Второй круг самопроверки исполнен ДОБРОВОЛЬНО:** владельцем эта половина не подтверждена, каноном не стала, и как на решение владельца я на неё не ссылаюсь. #### 0. Исход по КАЖДОМУ пункту заказа — пунктов без исхода нет | пункт промта | исход | чем предъявлено | |---|---|---| | §4.1(а) пере-снять замер | **сделано** | таблица §1 ниже, каждый ноль с контролем | | §4.1(б) закрыть непокрытое | **сделано в двух местах** | `membank.ConsolidationKeyConflicts` + расширенная `UnverifiedKeyConflicts`; пины + 18 мутаций | | §4.1(в) «варнинг → стоп» | **сознательно не делаю** — по промту это пинг; вынесено оркестратору, он развёл «видеть» и «делать» по уровням и завёл строку бэклога | в коде ни `return err`, ни drop: обе проверки только `WarnContext` | | §4.2 совет про статус | **сделано, вариант 1** (текст приведён к коду); вариант 2 отвергнут по существу — вернул бы развилку по статусу, закрытую `D39.104` п.2 | замер «status: auto не растворяет ливлок»: инжектятся ОБЕ (2/2/2), контроль 0; пин + 2 мутации | | §4.3 комментарий постчека + пин | **сделано**, плюс два носителя той же лжи вне промта | `TestWrongDstObeyedIsNotAMiss` + мутация | | §4.3 детектор ЗНАЧЕНИЯ | **сознательно не делаю** — запрещён промтом, живёт строкой 286 | в диффе нет source-side проверки | | §4.4 sticky в редакторской волне | **сделано** (комментарий); сам перенос НЕ строю — по строке 321 сначала замер дрейфа | `waverun.go`, `nil` на месте; оба механизма названы с `file:line` | | §4.4 резюм и строка статуса | **сделано** — поведение установлено по коду и запинено | `TestOrdinaryResumeMovesOnlyTheSkippedRow` + 2 мутации; мнение автора промта проверено, а не унаследовано | | §4.5 строки 322 / 295 / 161 / 283 | **не делаю** — прямо исключены промтом | в диффе их нет | | §5а список | **сделано, 9 позиций** с `file:line`; ни одна не чинилась | секция §8 | | П1 страховка на слиянии | **сделано** варнингом | формат сообщения + 4 мутации; корпусный замер | | П2 только репорт | **соблюдено** | отказ не построен | | П3 маркер на листе подписи | **сделано**, маркер отличен от `Contradicts` | пин + 2 мутации; предъявлено, что сдвинулся только сайдкар | #### 1. Пере-снятый замер §4.1(а): постановка подтвердилась и оказалась уже правды $0, мои руки, выброшенные пробы. Каждый ноль с контролем. Точка слияния, `windowsOverlap([0,0],[3,9])=true` (контроль `[0,2]×[3,9]=false`): | популяция | `ApprovedSharedKeyCollisions` | `UnverifiedKeyConflicts` | |---|---|---| | approved × approved (КОНТРОЛЬ) | **1** | 0 | | approved × auto (КОНТРОЛЬ) | 0 | **1** | | draft×auto, draft×draft, auto×auto | **0** | **0** | | общий alias, draft × auto | **0** | **0** | | общий alias, approved × approved (КОНТРОЛЬ) | **1** | 0 | Внутрифайловый `parseBankSeed`: тот же `Src`, draft×auto, один файл → REFUSED (статус-слеп); общий alias, draft×auto → LOADED, ни один гард не сработал. ⚠ **Поправка к строке 267, принята оркестратором:** контроль «общий alias, approved×approved, один файл» тоже LOADED — `LoadGlossarySeed` alias'ы не сравнивает вообще. Непокрытие через alias внутри файла — не только для неподписанных; для подписанных страховка стоит этажом выше (`bankmaterialize.go:142`). #### 2. Главная находка (в промте и строке 267 её нет) **Стадия схлопывания не сверяет выработку с существующей строкой банка на тот же firing-ключ — ни при какой подписи.** Слово владельца в строке 267 указывает сюда, и оно шире исходной постановки. Предъявлено пробами: - `CanonConflicts` при кандидате `元始`→«камень первоисточника» и ПОДПИСАННОЙ `元始`→«юаньши` вернула 1 конфликт, но **не этот**: назвала составное `元始空窍`. Прямая пара пропущена по построению (`terminology.go:941` пропускает `n.Src == c.Key`; `CanonFor:873` — «a candidate that IS the signed row has nothing to learn from it»). КОНТРОЛЬ на случае, ради которого проверка строилась → **1**. - `ConsolidationConflicts` на «та же поверхность дважды» → **0**; КОНТРОЛЬ «составное роняет свою же часть» → **1**. - Ветка не мёртвая: `unsignedEngineSurfaces` выкидывает неподписанную mined-строку из сид-поверхностей майнера (выжила 1 из 2, именно `approved`), а `terminology.Merge(nil, 2 observed)` кладёт в кандидаты обе поверхности, включая ту, что банк держит `approved` (КОНТРОЛЬ: `Merge(nil,nil)` → **0**). Фильтр сид-поверхностей стоит на ЭМИССИИ (`mining.go:549`), не на входе в роль. #### 3. Что построено **(а) `membank.ConsolidationKeyConflicts`** — сверка каждой схлопнутой формы с любой строкой банка на общий firing-ключ (src или alias) при перекрытии окон и другом dst, независимо от статуса обеих сторон. Возвращает `[]BankKeyConflict` (части, не предложения: рендерят две поверхности — лог и лист подписи). Пара с совпадающим UNIQUE-кортежем не репортится: схема не даёт обеим строкам существовать. Сравнение кортежа идёт по СЫРОМУ `Src`, потому что таков ключ хранилища (см. §4-бис п.1: `族長` и `族长` с одним окном — две законные строки); соответствие обеспечивает вызывающий, передавая источник, который строка получит при посадке. ⚠ **Проверка сформулирована как РАЗНОГЛАСИЕ, а не как предсказание «обе формы поедут на провод».** Так вышло по находке второго круга: для сид-поверхности эмиссия роняет предложение, а авто-банк переписывается целиком, поэтому «BOTH survive» было бы ложью ровно на сценарии, который пиннит мой же тест. Три механизма разрешения названы в доке. Проводка — `terminologist.go`: `glossaryRows()` (одно чтение банка, столько же обращений к store, сколько было), `consolidatedRows()`, `terminologyResult.BankConflicts` + `BankHolds`. **(б) `membank.UnverifiedKeyConflicts` расширена** (П1): было «approved × неподписанная», стало «любая пара, кроме approved×approved» (та у fail-loud). Осталась ВАРНИНГОМ по прежнему доводу. Нужна отдельно от (а): состояние достижимо и без схлопывания — рукописный сид `draft` + рукописная дельта `draft` с разными окнами при выключенном гейте терминолога. Сообщение называет обе строки, их подписи, оба окна и firing-ключ (`statusLabel`, `windowLabel` — `[ch 3..9]`/`[ch 1..end]` вместо сырых нулей, которые читались бы как пустое окно). **(в) Находка доезжает до листа подписи** (П3): `BankStopRow.BankHolds` + маркер `THE BANK ALREADY HOLDS:` — отдельное поле и отдельный маркер от `Contradicts`/`CONTRADICTS this run's own`. **(г) §4.3 — комментарий постчека приведён к поведению + пин `TestWrongDstObeyedIsNotAMiss`.** Промах = форма ОТСУТСТВУЕТ, и только это; послушанный неверный dst присутствует, `if present { continue }` берётся, промаха нет. Ноль confirmed-промахов говорит про ИСПОЛНЕНИЕ ПОДПИСАННОЙ половины банка — про неподписанную не говорит ничего (её промахи уходят в `Unverified` и не считаются). **Те же ложные утверждения найдены грепом и сняты ещё в двух местах, которых в промте не было:** `pipeline/disposition.go:90` и `cmd/tmctl/render.go:366`. **(д) §4.2 — совет «or mark one status: auto» снят.** Установлено исполнением: при `status: auto` на второй строке инжектятся ОБЕ (approved→2, draft→2, auto→2; КОНТРОЛЬ «src отсутствует в чанке» → 0). Под `D39.104` п.2 провод не ветвится по статусу ⇒ статус-слепота гварда ВЕРНА, а совет — осколок до-`D39.104` эпохи. Выход №2 («научить гвард смотреть статус») отвергнут по существу: он вернул бы закрытую доктриной развилку. **(е) §4.4 — два ложных комментария сняты.** `waverun.go`: оправдание `nil`-переноса sticky заменено фактом — `assignEditUnits` закрывает единицу внутри главы, sticky сбрасывается на границе ГЛАВЫ, 1962 из 2283 глав многоединичны (замер строки 321, не мой, атрибутирован); перенос НЕ строю. `chunkstatus.go`: см. §5, там моя формулировка была неверна дважды. **(ж) Попутно исправлена собственная ложь, созданная расширением:** `seeding.go:73` говорил «an UNSIGNED row contradicts an APPROVED term» — неправда для новой половины. Текст приведён к правилу. ⛔ **Прежняя приписка «на старый текст не стоял ни один тест (`grep` = 0)» ОПРОВЕРГНУТА приёмкой и снята — и это мой собственный «прибор ответил на свой вопрос».** Я грепала ЦЕЛУЮ фразу, которая живёт только в самом `seeding.go`, поэтому ноль был предрешён. Правда обратная: сообщение БЫЛО запинено ПОДСТРОКОЙ (`pipeline.TestUnsignedConflictIsReportedByTheRun` утверждал `"contradicts an approved term"`), батарея от расширения ПОКРАСНЕЛА, и правку этого самого теста объявляет §9 п.2 того же отчёта. То есть отчёт противоречил сам себе через две секции. #### 4. Что нашли ДВА круга самопроверки в моей же работе Круг 1 — интервальный контролёр по явным критериям + опровергатель (оба Fable, оба на копии дерева). 18 находок, все разобраны. Самые дорогие: 1. **`chunkstatus.go` — моя правка §4.4 была ЛОЖНОЙ.** Я написал «обычный резюм ничего здесь не пишет». Оба агента предъявили обратное, и я воспроизвёл сам: **$0-резюм (провайдер-вызовов 3→3) сдвинул `updated_at` СКИПНУТОЙ строки** (`ch1/chunk0/edit: 19:48:13 → 19:48:14`) при неподвижных `ok` и `flagged` (КОНТРОЛЬ: 3 строки из 4 не двинулись). Механизм: скип — не хранимый вердикт, флагнутая строка отдаётся из чекпойнта, а `runStageSequence` (`waverun.go`) пере-апсертит скип каждым прогоном. ⚠ **Моя ПЕРВАЯ попытка назвать механизм тоже была неверна** (указала на fast-path `stagerun.go`); поймано мутацией — мутант «fast-path обслуживает скипнутые» ПЕРЕЖИЛ пин. Формулировка исправлена на `waverun.go`, близнец `export.go` (`TextModified`) приведён в согласие, поставлен пин `TestOrdinaryResumeMovesOnlyTheSkippedRow`. 2. **Ложное срабатывание, класс A:** для сид-поверхности, задетой через banknote, выработка НИКОГДА не ложится (эмиссия её роняет), поэтому мой текст «the term would carry TWO renderings» был ложью ровно на сценарии моего же теста. Проверка пере-сформулирована как разногласие; текст варнинга и док переписаны. 3. **Ложное срабатывание, класс B:** сравнение UNIQUE-кортежа шло по сырым `Src`, а banknote-кандидат несёт сырую поверхность против нормализованного ключа ложащейся строки (`族長` против `族长`). ⚠ **Лечение круга 1 было неверным** (свёртка обеих сторон) и переделано на круге 2 — см. §4-бис п.1. 4. **Мой собственный комментарий повторял чужой misnomer:** «dropped where a SIGNED row holds the key» — `loadAutoBank` роняет предложение по ЛЮБОЙ ранее собранной строке любого статуса. Исправлено и названо ценой пропуска. 5. **`consolidatedRows` не пиннился ничем:** мутации «убрать `SinceCh`» и «убрать алиасы» переживали весь пакет `pipeline`. Добавлен `TestConsolidatedRowsCarryTheWindowAndTheAliases`; обе мутации теперь ловятся с верным текстом. 6. **Три дефекта в моём корпусном приборе:** классификация пары по подстроке `: approved "` ловила только случай, когда approved-строка печатается первой; `booksSeen` был тождествен `booksWithRows` по построению (мёртвая «контрольная» величина); подсадка строилась от `g[0]`, у которой может не быть огневого ключа или dst ⇒ ложный ОТКАЗ прибора. Все три закрыты, числа после починки те же. 7. **Двойной репорт в ОДНОМ прогоне — подтверждён моим прогоном на ДЕЛЬТА-фикстуре** (`test-book.mined-delta.yaml` с неподписанной строкой `方源→Странник`): авто-режим после `writeAutoBank` пере-сидит, и `UnverifiedKeyConflicts` называет ту же пару через 2 мс после стадии схлопывания — collapse=1, merge=1, КОНТРОЛЬ всего 3 строки WARN. ⚠ **Фикстура названа по находке круга 5:** на СИД-фикстуре моего же e2e выходит collapse=1, merge=0, потому что эмиссия роняет предложение по сид-поверхности, и без имени фикстуры число читалось бы как общее. НЕ подавлял: это разные состояния одного термина («роль расходится с банком» до того, как строка легла, и «банк держит обе» после), и только второе означает две строки на проводе. Названо в доке; если оркестратор сочтёт это шумом — резать надо слияние. 8. **Линтер нашёл два настоящих дефекта в приборе:** непроверенный `rows.Err()` в обоих запросах. Для измерительного прибора это ровно та неисправность, ради которой он написан: усечённая итерация вернула бы меньший банк как чистый. Разведено на две функции с `defer rows.Close()` и возвратом `rows.Err()`. Мелкие, тоже закрыты: перебор в «zero says the bank was EXECUTED»; `render.go` — строка detail несёт и ambiguous-промахи, поэтому «an approved rendering» верно для гейта, не для строки; ассерт «one fault, not two: []» давал верный вердикт при нуле с неверным текстом. #### 4-бис. КРУГ 2 самопроверки — восемь находок, три серьёзные, все в моей же работе Мандат круга 2 (добровольный, см. оговорку выше): проверить ИСПОЛНЕНИЕМ и исходный заказ, и закрытие находок круга 1. Проверяющий — отдельный агент на копии дерева, 19 мутаций, каждая восстановлена со сверкой sha256. 1. ⛔ **МОЙ ФИКС НОРМАЛИЗАЦИИ БЫЛ НЕВЕРЕН, А ДОВОД ПОД НИМ — ЛОЖЕН.** По находке круга 1 я свернула сравнение UNIQUE-кортежа через `NormalizeSourceKey` и написала «схема не даёт обеим строкам существовать». **Пере-мерила сама:** `ReplaceGlossary(族長 + 族长, один sense и окно)` → `err=nil, rows stored=2`; КОНТРОЛЬ с байт-равным `src` → `UNIQUE constraint failed: glossary.book_id, glossary.src, glossary.sense, glossary.since_ch, glossary.until_ch`. **UNIQUE стоит на СЫРОМ `src`**, и трад/упрощённая пара — две законные строки, обе из которых инжектятся. Значит моя свёртка вводила ЛОЖНООТРИЦАНИЕ: пропускала настоящее противоречие. Вылечено по-настоящему, а не заплатой: сравнение вернулось к сырому (зеркалит ключ хранилища), а `consolidatedRows` строит строку с `Src: c.Key` — тем источником, который она РЕАЛЬНО получит при посадке (`mining.go` кладёт `Src: c.Key`). Обе половины запинены (`TestConsolidationTupleSkipMirrorsTheStoreKey`, усиленный `TestConsolidatedRowsCarryTheWindowAndTheAliases`), обе мутации красны с верным текстом. ⚠ **До круга 2 мутация «свернуть сравнение» ПЕРЕЖИВАЛА весь пакет** — фикс был не запинен вовсе. 2. ⛔ **`chunkstatus.go` — не тот механизм В ТРЕТИЙ РАЗ подряд.** Скип в шипящей раскладке (редакторская волна, единица с флагнутым черновиком) пишет `recordSkippedStages`, а не флагнутая ветка `runStageSequence`: та берётся только при ≥2 стадиях в ОДНОЙ волне. Поймано мутацией — правка ветки `runStageSequence` мой пин ПЕРЕЖИЛА, а правка `recordSkippedStages` его уронила с верным текстом. Названы оба писателя, в доке пина тоже. 3. ⛔ **Пропуск по кортежу молчит на самой частой форме сид-строки** (окно по умолчанию, без sense). Замер: та же фикстура без `until_ch: 20` → `BankConflicts=0` и при `draft`, и при `approved`; с `until_ch: 20` → 1. **Мой же e2e-тест обходил это подобранным окном, и я этого не вынесла.** На провод не влияет (предложение отбрасывается), теряется строка на листе подписи. Названо ценой в доке `ConsolidationKeyConflicts` и вынесено в §5а №7. 4. **Тихий ноль, внесённый ЭТИМ паком:** `glossaryRows` возвращал `nil` при ошибке чтения банка без единого слова, из-за чего `BankConflicts=0` неотличим от «конфликтов нет». Теперь логируется явно, с формулировкой «их нули означают „не спросили“, а не „не нашли“». 5. **Перебор в §4.3:** «ноль confirmed-промахов = подписанная половина исполнена» — неточно: `Confirmed` требует и `approved`, и ДОВЕРЕННОГО ключа, а промах на одно-Han ключе демотируется в `Unverified`. Приведено к «подписанные строки, сработавшие на доверенном ключе». 6. **Стиль (правило владельца):** довод «containment + equal-source + approved-only» стоял ТРИЖДЫ — оставлен там, где живёт проверка, остальные заменены ссылкой; снята история в тесте («эта фикстура всегда несла»), план в коде («carry stays unbuilt until it is»), чужой замер 1962/2283 атрибутирован стенд-книге и дополнен `file:line` обоих механизмов. Проверяющий отдельно искал ПОТЕРЮ нужной детали при сокращении и не нашёл (перечитаны все 14 файлов диффа). 7. **§5а вырос с 6 позиций до 9**: №6 `bankmaterialize.go:127` (та же ложь про «signed»), №7 пропуск по кортежу на форме сид-строки по умолчанию, №9 — путь записи статуса не читается по коду (писателей два, выбор решает раскладка волны). Тихий ноль `glossaryRows` не вынесен, а ЗАКРЫТ. 8. **Подтверждено круга-2 замером:** довод про двойной репорт верен по коду (`mining.go:241-246`); корпусный прибор после починки даёт те же числа и симметричную классификацию; обе мутации `consolidatedRows` ловятся; ассерт «0 против 2» различает случаи. ⇒ **Итог по кругам: 18 находок в круге 1 + 8 в круге 2, из них ПЯТЬ — ложные утверждения в моих же комментариях.** Это тот самый класс, который пак чинил, и он воспроизвёлся на мне пять раз. Единственное, что его ловило надёжно, — мутация, прочитанная ПО ТЕКСТУ: три раза пин переживал мутацию, и каждый раз это означало не дыру в пине, а неверный механизм в моём описании. #### 4-кватер. КРУГ 3 — РЕГРЕСС от моего же лечения круга 2, плюс четыре мелочи Круг 3 подтвердил, что все шесть находок круга 2 закрыты, и нашёл одну новую — самую дорогую в паке, потому что её внесла МОЯ ПРАВКА: 1. ⛔ **РЕГРЕСС: метка листа подписи терялась ровно у той популяции, ради которой правка делалась.** Лечение круга 2 сменило ключ, которым `terminologist.go` пишет карту `res.BankHolds` (стал ключ посадки, `cf.Src == c.Key`), а `mining.go` продолжал читать её по `c.Src` — СЫРОЙ поверхности кандидата. У banknote-кандидата с `Key != Src` (традиционное написание, регистр, кана) метка `THE BANK ALREADY HOLDS` до листа не доезжала: счётчик и лог верны, требование П3 нарушено молча. Мои же пины этого не ловили: юнит-пин останавливался до `bankStopRows`, а e2e-пин стоит на `方源`, где `Key == Src`. **Вылечено** переводом чтения на `tres.BankHolds[c.Key]` (так же, как рядом читается `Conf`), пин продлён через `bankStopRows` на кандидате `{Key: 赵甲, Src: 趙甲}`, мутация обратно на `c.Src` красна: «the mark must reach the sheet for a candidate whose key differs from its surface: {Src:趙甲 … BankHolds:[]}». 2. **Отчёт §3(а) описывал отменённую версию кода** («сравнение свёрнуто через `NormalizeSourceKey`»). Приведён к коду; греп отозванной фразы → 0 при контроле 1. 3. **Нумерация §5а шла 1..7, 9, 8** — выправлена. 4. **Два абзаца доки `ConsolidationKeyConflicts` носили один заголовок «Cost of the skip»** и читались как дубль, хотя это разные цены. Разведены: «WHAT THE SKIP HIDES» (форма сид-строки по умолчанию) и «WHO RESOLVES A SKIPPED PAIR» (`loadAutoBank` роняет по строке любого статуса). 5. **Варнинг `glossaryRows` обещал молчание обеих проверок**, хотя из `scoreOpts` затрагивается только якорь скоринга, и при стойкой ошибке чтения печатается трижды за роль. Текст сужен до «whatever this call feeds», повторяемость названа. ⇒ **Урок круга 3, который дороже самой находки:** правка, сделанная ПО находке ревью, — такой же новый код, как всякий другой, и требует своего пина. Мой фикс круга 2 был верен по существу и сломал доставку на этаж выше, потому что я запинила изменённую функцию, а не путь до потребителя. #### 4-квинтус. КРУГ 4 — зеркало того же шва плюс асимметрия доставки Круг 4 подтвердил все пять пунктов круга 3 закрытыми и нашёл четыре новых. Главная — того же класса, что регресс круга 3, но с другой стороны шва: 1. ⛔ **Сторона ЗАПИСИ карты `BankHolds` не была запинена вовсе.** Мутации ключа записи на `cf.Key` (firing-ключ, может быть АЛИАСОМ) и на `cf.BankSrc` (поверхность строки банка) **переживали весь пакет `pipeline`**. Причина названа точно: мой юнит-пин строил карту СВОЕЙ копией продакшн-цикла, а не звал продакшн-писателя, а e2e-пин стоит на `方源`, где ключ кандидата, сырая поверхность, firing-ключ и поверхность строки банка — одна и та же строка, так что любой из четырёх ключей проходил. **Вылечено выделением одного писателя** `bankHoldsByCandidate`, которого зовут и продакшн, и пин; фикстура подобрана так, что все четыре строки различаются. Обе мутации красны с верным текстом. 2. **Стдаут-таблица стопа печатала `⚠ contradicts:` и НЕ печатала маркер банка** (`cmd/tmctl/render.go`) — оператор на первом экране видел одно разногласие и не видел второго, при том что пак сам обосновал их равенство. Добавлена строка `⚠ bank holds:` рядом с братом. 3. **Абзац «WHO RESOLVES A SKIPPED PAIR» смешивал две популяции** и утверждал «nothing reporting it». По коду: для СИД-поверхности резолвер — фильтр эмиссии (`reverseSectionTerms`), а не `loadAutoBank`; для ДЕЛЬТА-строки — `loadAutoBank`, и дроп ЛОГИРУЕТСЯ, но текстом «held by a **signed** term» при любом статусе держателя, то есть оператору говорят НЕВЕРНОЕ, а не ничего. Абзац разведён, §5а №1 отчёта приведён к этому же. 4. **Дока поля `BankHolds` говорила «per candidate src», а комментарий писателя — «keyed by the KEY»**: два комментария к одному полю расходились ровно в том слове, на котором сломался круг 3. Сведены. Плюс два числа отчёта не воспроизводились и были пере-сняты: счётчик ссылок на `BankHolds` устарел после продления пина, а контрольная формулировка «`Contradicts` дальше листа и лога не идёт» оказалась **ложной** — он печатается в стдаут, и именно эта находка привела к п.2. ⇒ **Урок круга 4:** тест, который ВОСПРОИЗВОДИТ продакшн-логику копией вместо вызова, пинит собственный цикл, а не код. Два круга подряд дыра сидела на одном шве «писатель ↔ читатель», и оба раза её прятала фикстура, где все кандидаты на ключ совпадают. #### 4-секстус. КРУГ 5 — сошлись по ПОВЕДЕНИЮ; остаток был в пинах и тексте, и шов убран целиком Круг 5 подтвердил: регресса в лечении круга 4 нет, все пять пунктов закрыты и воспроизведены исполнением (включая замер, которого я не сделала сама на круге 1 — дроп дельта-строки действительно логируется словом «signed» при держателе `status=draft`). Остаточных находок четыре, все в пинах и тексте: 1. ⛔ **Шов «писатель ↔ читатель» бил ТРИ круга подряд, поэтому убран, а не подпёрт четвёртой заплатой.** Круг 5 показал, что даже после выделения общего писателя мутация «продакшн обходит писателя и вписывает свой ключ» переживает весь пакет: e2e стоит на `方源`, где ключ кандидата, сырая поверхность, firing-ключ и поверхность строки банка — одна строка. **Решение по `D39.216`: карты больше нет.** `terminologyResult.BankHoldRows` несёт находки НЕГРУППИРОВАННЫМИ, сопоставляет их с рядом одна функция `bankHoldLabels` в том файле, который их потребляет, — то есть ключ выбирается в ОДНОМ месте, а не по разу с каждой стороны. Три мутации ключа сопоставления (`cf.Key == c.Key`, `cf.Src == c.Src`, `cf.BankSrc == c.Key`) теперь красны на одном пине с текстом про сломанное. 2. **Строка `⚠ bank holds:` в стдауте была без пина — и её брат `⚠ contradicts:` тоже.** Добавлен `TestRenderSignatureStopShowsBothDisagreements`; обе мутации (удалить любой из двух блоков) красны, контроль — ряд без маркеров не печатает ни одного. 3. **Абзац доки обобщал дельту:** до `loadAutoBank` доходит только НЕПОДПИСАННАЯ дельта-строка, потому что approved-дельта остаётся сид-поверхностью для эмиссии (`unsignedEngineSurfaces`). Уточнено одним словом. 4. **Корпусный прибор проходил на пустом обходе** (`TM_CORPUS=/nonexistent` → PASS при `walked=0` — ровно тот класс, ради которого он написан), и `trimTo` резал байты, а не руны, на ханьских и кириллических сообщениях. Оба закрыты: пустой обход теперь `t.Fatalf`, срез рун-безопасен. Плюс пере-сняты шесть устаревших `file:line` отчёта (сдвинулись моими же правками) и названа фикстура у числа «collapse=1, merge=1»: оно ДЕЛЬТА-фикстуры, а на сид-фикстуре выходит 1 и 0, потому что эмиссия роняет предложение. ⇒ **Урок круга 5, и он про архитектуру, а не про внимательность:** если одна и та же дыра ловится три круга подряд в разных её точках, чинить надо не точку, а шов. Карта, ключ которой выбирается дважды, — это два места для одной мысли; после перестройки мест стало одно, и все три мутации ключа ловит один пин. #### 4-тер. Находки кругов → что сделано → чем предъявлено | находка (круг) | что сделано | чем предъявлено | |---|---|---| | «обычный резюм ничего не пишет» ложно (1) | текст исправлен, близнец `export.go` согласован, поставлен пин | мой прогон: вызовов 3→3, скипнутая строка `19:48:13→19:48:14`, три остальные не двинулись | | механизм резюма назван неверно (1, затем 2) | названы ОБА писателя с условием каждого; вынесено в §5а №9 как свойство места | мутация `recordSkippedStages` красна; мутации двух неверных механизмов переживали | | «the term would carry TWO renderings» ложно для сид-поверхности (1) | проверка пере-сформулирована как РАЗНОГЛАСИЕ, три механизма разрешения названы | греп отозванной фразы 0 при контроле 1; текст варнинга и e2e-ассерт обновлены | | сравнение кортежа по сырым `Src` (1) | свёрнуто через `NormalizeSourceKey` — **и это оказалось неверно, см. следующую строку** | — | | **свёртка ввела ложноотрицание, довод ложен (2)** | сравнение вернулось к сырому (зеркалит ключ хранилища), `consolidatedRows` строит строку с `Src: c.Key`; обе половины запинены | мой замер: `rows stored=2` против контрольного `UNIQUE constraint failed`; обе мутации красны | | мой комментарий повторял misnomer «SIGNED» (1) | исправлен, цена пропуска названа | греп 0 при контроле 1 | | `consolidatedRows` не пиннился ничем (1) | добавлен `TestConsolidatedRowsCarryTheWindowAndTheAliases`, усилен на круге 2 | обе мутации красны с верным текстом; до пина переживали весь пакет | | три дефекта корпусного прибора (1) | классификация симметрична, мёртвая ветка снята, подсадка перебирает строки | те же числа после починки: 142 книги, 13350 строк, подсадка 142/142 | | два дефекта прибора от линтера (1) | разведено на две функции, `rows.Err()` возвращается | `golangci-lint` → `0 issues.` | | двойной репорт в одном прогоне (1) | НЕ подавлен, назван в доке как разные состояния термина | мой прогон: collapse=1, merge=1, всего 3 строки WARN | | пропуск по кортежу молчит на форме сид-строки по умолчанию (2) | не чинится, названо ценой в доке, вынесено в §5а №7 | замер: без `until_ch: 20` → 0 при draft и approved, с ним → 1 | | тихий ноль `glossaryRows` (2) | ошибка чтения банка логируется | в коде `r.Log.Warn` на ветке ошибки | | перебор «SIGNED half» (2) | сужено до «подписанные строки на ДОВЕРЕННОМ ключе» | `memory.go` `dispositionFor`/`keyTrusted`, `singleHanKeyFired` | | стиль: довод трижды, история, план в коде (2) | оставлен один носитель, остальное ссылкой; история и план сняты; чужой замер атрибутирован | греп по каждой снятой формулировке 0 при ненулевом контроле | | **РЕГРЕСС: метка листа терялась при `Key != Src` (3)** | чтение переведено на `tres.BankHolds[c.Key]`; пин продлён через `bankStopRows` на кандидате `{Key: 赵甲, Src: 趙甲}` | мутация обратно на `c.Src` красна: «the mark must reach the sheet for a candidate whose key differs from its surface» | | отчёт описывал отменённую версию кода (3) | §3(а) приведён к коду | греп отозванной фразы 0 при контроле 1 | | нумерация §5а 1..7, 9, 8 (3) | выправлена | `grep -oE '^[0-9]+\.'` → 1 2 3 4 5 6 7 8 9 | | два абзаца доки под одним заголовком (3) | разведены на «WHAT THE SKIP HIDES» и «WHO RESOLVES A SKIPPED PAIR» | оба факта проверены по коду | | варнинг `glossaryRows` обещал больше, чем делает (3) | сужен до «whatever this call feeds», повторяемость названа | зовётся и из `scoreOpts`, где затрагивается только якорь | | **сторона ЗАПИСИ карты не запинена (4)** | выделен один писатель `bankHoldsByCandidate`, продакшн и пин зовут его; фикстура различает все четыре кандидата на ключ | обе мутации (`cf.Key`, `cf.BankSrc`) красны: «the mark must reach the sheet for a candidate whose key differs from its surface» | | стдаут стопа показывал брата и прятал маркер банка (4) | добавлена строка `⚠ bank holds:` рядом с `⚠ contradicts:` | `cmd/tmctl/render.go`; пакет `tmctl` зелёный | | абзац доки смешивал две популяции и врал про молчание (4) | разведён: сид роняет эмиссия, дельту роняет `loadAutoBank` и ЛОГИРУЕТ, но словом «signed» | §5а №1 приведён к тому же | | дока поля и комментарий писателя расходились в слове (4) | сведены на «keyed by the candidate KEY» | греп по обоим местам | | два числа отчёта не воспроизводились (4) | пере-сняты командой; ложный контроль про `Contradicts` снят | он печатается в стдаут — эта же находка дала строку выше | | **шов «писатель↔читатель» пережил и общего писателя (5)** | шов УБРАН: находки едут негруппированными, сопоставляет одна функция в файле-потребителе | три мутации ключа сопоставления + «продакшн обходит хелпер» — все красны на одном пине | | `⚠ bank holds:` в стдауте без пина, и брат тоже (5) | `TestRenderSignatureStopShowsBothDisagreements` с контролем | удаление любого из двух блоков красно с текстом про свой маркер | | абзац обобщал дельту: до `loadAutoBank` доходит лишь НЕПОДПИСАННАЯ (5) | уточнено одним словом | `unsignedEngineSurfaces` оставляет approved-дельту сид-поверхностью | | прибор проходил на пустом обходе, `trimTo` резал байты (5) | пустой обход — `t.Fatalf`; срез рун-безопасен | `TM_CORPUS=/nonexistent` → FAIL «a walk that found nothing reports the same zeros as a clean corpus» | | шесть `file:line` отчёта протухли (5) | пере-сняты грепом, каждый проверен | 23 адреса резолвятся на заявленное (круг 6) | | два счётчика отчёта протухли снова (6) | ВСЕ числа сняты ОДНИМ проходом после последней правки | круги 4, 5, 6 ловили это трижды — причина была в порядке, а не в счёте | | **обещание про `src` верно лишь для banknote-посадки (приёмка Д1)** | достроено до обеих посадок; свойство, на которое оно опирается, запинено | идемпотентность 10/10 при контроле «4 из 10 входов меняются»; `TestNormalizeSourceKeyIsIdempotent` | | **гарантия `approvedNeighbours` только в комментарии (приёмка Д2)** | `TestApprovedNeighboursAdmitsOnlySignedRows` | обе мутации фильтра красны со списком пролезших строк | | **отчёт противоречил сам себе через две секции (приёмка Д3)** | §3(ж) и §5а №8 исправлены, класс сужен до «пин узкий» | греп целой фразы был предрешён — она живёт только в `seeding.go` | #### 4-септимус. КРУГ 6 — СОШЛИСЬ Круг 6 прогнал четыре мутации по перестроенному шву (три ключа сопоставления плюс «продакшн обходит сопоставитель инлайном») — **все четыре красны на одном пине**, e2e не ловит ни одной, что совпадает с заявленным разделением ролей пинов. Проверил и то, что перестройка ничего не потеряла: порядок находок тот же (предложение → firing-ключ → индекс банка), дублей нет по построению, детерминизм 200 прогонов — 1 различный вывод при 5 и 9 находках, КОНТРОЛЬ map-упорядоченной склейки — 189 различных. **Новых находок в коде пака нет.** Осталось два: 1. **Шов-БЛИЗНЕЦ в коде, который пак не трогал:** `Contradictions` и `Conf` пересекают ту же границу тем же способом, стороны согласованы, но ни одна фикстура не имеет кандидата с `Key != Src` — мутация любого из трёх ключей переживает полные пакеты `pipeline`, `terminology` и `tmctl`. Не регресс и не мой код; вынесен §5а №10. 2. **Два счётчика отчёта снова протухли** — третий раз подряд, и причина не в счёте, а в порядке: я снимала числа до правок. Закрыто иначе, чем прежде: **все числа отчёта пере-сняты ОДНИМ проходом после последней правки кода**, и это записано рядом с ними. ⚠ Круг 6 сам поймал у себя ошибку до сдачи: прочёл чужой лог батареи как свой и объявил красноту. Назвал это в отчёте — то же требование, что канон предъявляет к сессии. #### 4-октавус. ДОФИКС ПО ПРИЁМКЕ — три пункта, все закрыты Приёмка (три линзы, 14 находок, 0 блокеров, 3 major) подтвердила исполнением «репорт-онли», нетронутый снапшот и пере-посаженные мутации. Три пункта дофикса: **Д1 — обещание про `src` было верно для ПОЛОВИНЫ популяции, и я выбрала не сужать его, а достроить.** Приёмка права: `reverseSectionTerms` эмитит `Term{Src: c.Key}` только для banknote-кандидата, а MINED-строка ложится с сырым `m.Src` (`miner_emit.go:251`). **Замер решил, что чинить:** `c.Key` — верный источник и там, и там, но по разным причинам. Мined-поверхность — подстрока УЖЕ нормализованного текста чанка (майнер везде читает `c.NSource`), поэтому её собственный ключ равен ей самой; проверено исполнением — `NormalizeSourceKey` идемпотентен на 10 из 10 проб, при КОНТРОЛЕ, что 4 из 10 входов он реально меняет (то есть ноль расхождений — свойство, а не молчание). ⇒ Комментарий достроен до обеих посадок, **и свойство, на которое он теперь опирается, ЗАПИНЕНО** (`text.TestNormalizeSourceKeyIsIdempotent`): без идемпотентности проверка сравнивала бы ложащуюся строку с источником, которого у неё нет, — молча, на mined-половине каждого банка. **Д2 — гарантия `approvedNeighbours` жила только в комментарии; теперь у неё пин.** Мутация «убрать `e.Status == "approved"`» переживала три пакета. Траектория дорогая: это канон для промта ПЛАТНОЙ роли, и неподписанная строка, попав в «свидетельство», меняет байты, едущие к модели. Добавлен `TestApprovedNeighboursAdmitsOnlySignedRows` — краснеет от снятия ЛЮБОЙ из двух половин фильтра, с контролем, что четыре подписанных и отрендеренных строки дают четыре. **Д3 — утверждение отчёта опровергнуто, и опровергается оно моим же §9 п.2.** Я объявила, что на текст варнинга S14 не стоял ни один тест, сославшись на `grep = 0`. **Ноль был предрешён: я грепала ЦЕЛУЮ фразу, которая живёт только в самом `seeding.go`** — прибор ответил на свой вопрос. Правда обратная: сообщение БЫЛО запинено подстрокой, батарея от расширения ПОКРАСНЕЛА, и правку того самого теста объявляет §9 п.2 двумя секциями ниже. Оба места исправлены; класс позиции §5а сузился с «пина нет» до «пин узкий»: подстрока стерегла одно словосочетание, а локализующая половина сообщения не была закрыта ничем. ⇒ **Д3 — седьмой случай моего собственного класса за пак, и первый, который нашли не мои круги, а приёмка.** Шесть кругов искали расхождение описания с кодом и не заметили расхождения отчёта с самим собой через две секции. #### 5. Таблица мутаций — правая колонка это ТЕКСТ падения, а не факт красноты | мутация | текст падения | восстановлено | |---|---|---| | `mempostcheck`: `if present{continue}` → `if !present{continue}` | «an OBEYED injection leaves its dst present, so the post-check has nothing to report: confirmed=1» | sha256 совпал | | гвард полисемии освобождает не-approved пару | «status "draft": the polysemy livelock must be refused whatever the second row's signature» | совпал | | в сообщение возвращён совет «mark one status: auto» | «the refusal must not offer a STATUS as a remedy — the guard ignores it and so does the wire» (×3) | совпал | | `ConsolidationKeyConflicts`: правая сторона только approved | «an unsigned row is owed one rendering too: got 0 []» | совпал | | то же: предложение стреляет только своим `Src` | «a contradiction reached through a shared alias must be reported: []» | совпал | | то же: снят пропуск по UNIQUE-кортежу | «a proposal on the row's own UNIQUE key replaces it and cannot contradict it: [firing key "元始"…]» | совпал | | `UnverifiedKeyConflicts`: возврат к approved-only | «want the approved×unsigned pair AND the unsigned×unsigned one, got 1» | совпал | | то же: из сообщения убраны окна | «must be reported with both statuses» + «a conflict must name its firing key and both windows» | совпал | | проводка в схлопывании получает пустой банк | «a rendering that disagrees with an UNSIGNED row of the same surface must be counted: {…BankConflicts:0…}» | совпал | | `consolidatedRows` теряет окно **(до круга 1 ПЕРЕЖИВАЛА)** | «the candidate's window must reach the check: since_ch=0, want 7» | совпал | | `consolidatedRows` теряет алиасы **(до круга 1 ПЕРЕЖИВАЛА)** | «the identity cluster must reach the check as alias keys: []» | совпал | | маркер строки банка удалён из рендера листа | «the rendered table must carry the mark:» | совпал | | обеим находкам дан ОДИН маркер | «the rendered table must carry the mark» | совпал | | находка подшита в поле само-противоречия | «the contradicting row must be marked on the signature sheet: {…Contradicts:[unsigned draft "方源"→"Странник" [ch 1..20]] BankHolds:[]}» | совпал | | резюм пере-пиннит каждую обслуженную строку | «an ordinary resume must not write an ok row: ch2/chunk0/edit moved …:07 → …:08» (×3) | совпал | | сравнение кортежа свёрнуто через `NormalizeSourceKey` **(ПЕРЕЖИВАЛА до круга 2)** | «族长 against a stored 族長 is a pair the store admits, not a replacement: []» | совпал | | `consolidatedRows` берёт сырую поверхность вместо ключа посадки **(ПЕРЕЖИВАЛА до круга 2)** | «the row must carry the source it will LAND with (the key), got "趙甲"» | совпал | | `recordSkippedStages` перестаёт пере-записывать скип | «a SKIPPED row is re-derived and re-written by every run past it: ch1/chunk0/edit stayed at …» | совпал | ⚠ **ЗЕЛЁНОЕ ДО КРУГА 2 → КРАСНОЕ ПОСЛЕ.** Четыре мутации переживали пин, и каждая означала не дыру в пине, а неверное ОПИСАНИЕ или незапиненный фикс. Зелёный пин при ложноотрицании дороже красного, поэтому таблица отдельно: | мутация | до круга 2 | после | что это значило | |---|---|---|---| | свернуть сравнение кортежа через `NormalizeSourceKey` | **зелено** (весь пакет `ok`) | красно: «族长 against a stored 族長 is a pair the store admits, not a replacement: []» | мой фикс круга 1 не был запинен ВОВСЕ, и сам был неверен | | `consolidatedRows` берёт сырую поверхность вместо ключа посадки | **зелено** | красно: «the row must carry the source it will LAND with (the key), got "趙甲"» | фикстура пина имела `Src == Key`, поэтому выбор был не нагружен | | флагнутая ветка `runStageSequence` не пере-записывает скип | **зелено** | заменена на `recordSkippedStages` — красно | механизм в комментарии назван неверно; писателей ДВА | | fast-path `stagerun.go` обслуживает скипнутые строки | **зелено** | ветка недостижима (у скипнутой строки пуст `ContentHash`) | второй неверный механизм в том же комментарии | ⚠ Одна мутация ОТБРОШЕНА, а не зачтена: «проводка удалена» не собралась, а сборочная ошибка — не поимка; пере-сделана компилирующейся. #### 6. Чем предъявлено — команды и вывод - **Батарея после последней правки:** `make battery` → **`MAKE_EXIT=0`**, `ok` пакетов **19** (+4 без тестов), строк `FAIL` **0**, линтер **`0 issues.`**; скипов **4**, все названы батареей: `TestMinerFullBookParity`, `TestCorpusBankKeyConflicts` (мой opt-in прибор — батарея его видит и называет), `TestHelperEventsRun`, `TestHelperKillLoop`. - **Дифф тестов исполнением** (`git diff -- 'backend/*_test.go' | grep '^[-+]func Test'`): в отслеживаемых файлах добавлено **9**, удалено **0**; `func Fuzz` 0/0. Плюс по **1** в двух новых файлах (`bankconflict_corpus_test.go`, `resume_updatedat_test.go`) → итого **+11 / −0**. - **Детерминизм:** 200 прогонов на одном входе — различных выводов `UnverifiedKeyConflicts` **1**, `ConsolidationKeyConflicts` **1**; КОНТРОЛЬ — заведомо map-упорядоченная склейка на тех же данных даёт **8** различных (само число зависит от фикстуры; значимо только «больше одного»). Плюс `-count=5 -race` по новым тестам. - **Корпус** (`TM_CORPUS=<репо>/books go test ./internal/pipeline/ -run TestCorpusBankKeyConflicts -v`): `.db walked=162, with a glossary table=161, without one=1, read-failed=0; books with a glossary=142, rows read=13350; ПОПУЛЯЦИЯ: книг хотя бы с одной неподписанной строкой=142, approved=1093 draft=11399 auto=858; книг с ЛЮБЫМ конфликтом=0; только approved×unsigned=0; с парой unsigned×unsigned=0; КОНТРОЛЬ: подсадка ловится на 142 из 142.` ⇒ **0 книг из 142, и это «не встречается», а не «не смотрели»:** 12 257 из 13 350 строк корпуса неподписанные, а форма столкновения не возникает потому, что все существующие двери роняют дубль по ПОЛНОМУ ключу `(src,sense,since_ch,until_ch)`, а разные окна через них проходят. ⚠ **Старое правило на корпусе тоже даёт 0** — S14 живёт в дереве без единого наблюдённого срабатывания; без этого числа «0» прочтётся как «новая половина бесполезна». - **§5.3, греп по каждой отозванной формулировке** (включая отозванные по находкам кругов 2, 3 и 4) — **25 из 25 дают 0**, у каждой рядом контрольная фраза из того же файла с ненулевым счётом. #### 7. Двигает ли что-нибудь снапшот, хеш запроса, ключ манифеста, версию встроенных данных **Нет.** Предъявлено: - Изменены только `.go`: **16** позиций `git status` по `backend/` (14 M + 2 новых `_test.go`); `configs/` и `internal/lang/data/` — **0**. - `git status` по всем четырём `testdata/` — пусто; КОНТРОЛЬ: голден-файлов в `internal/pipeline/testdata/golden/` — **6**. Ни один голден не пере-снимался; сайдкар листа подписи голденом не накрыт (`grep -rl 'BANK VERIFICATION TABLE' testdata/` → 0), его стерегут пять живых тестов, все зелёные. - Пины движения прогнаны поимённо ПОСЛЕ последней правки и зелены: `go test ./internal/pipeline/ -run 'TestGoldenDeterminism|TestCutTagFollowsTheLangpack|TestManifest' -v` → **14 PASS, 0 FAIL**; `go test ./internal/membank/ -run 'TestMemoryVersion|TestMaterializeMemoryVersion' -v` → **5 PASS, 0 FAIL**. - Новое поле листа подписи доходит ровно до ДВУХ человеческих поверхностей — сайдкара и стдаут-таблицы стопа: не-тестовых читателей `BankHolds` **2** (`mining.go` → `renderBankStopTable`, `cmd/tmctl/render.go`). Ссылок всего: `BankHolds` **12** в **4** файлах, `BankHoldRows` (носитель через границу) **5** в **3**; КОНТРОЛЬ — у соседнего `Contradicts` **11** в **4**. ⚠ **Прежняя формулировка этого контроля («`Contradicts` дальше листа и лога не идёт») была НЕВЕРНА и снята по находке круга 4:** он печатается в стдаут, и из-за той же находки мой маркер теперь стоит там же. ⚠ Числа пере-сняты одним проходом ПОСЛЕ последней правки: круги 4, 5 и 6 подряд ловили в отчёте протухшие счётчики, потому что я снимала их до правок, а не после. - Отдельным пином: диагностика НЕ входит в подписной документ (в `signature map` нет ни маркера, ни ярлыка строки банка; КОНТРОЛЬ — тот же файл содержит `青茅山` и `terms:`). - Обе проверки — только `WarnContext`; ни одна не возвращает ошибку и не меняет содержимого банка. Отказ (drop/stop) НЕ построен (П2). #### 8. §5а — «задумано против сделано». НЕ чинил, выношу списком 1. **`mining.go:654`** `loadAutoBank(signed []store.GlossaryEntry)`, зовётся как `r.loadAutoBank(in.entries)` (`bankmaterialize.go:125`). Обещано именем параметра, докой (`:648`) и сообщением оператору (`:691` «key held by the signed %q→%q»), что предложение движка отбрасывает ПОДПИСЬ. Исполняется: популяция — сид+ruby+дельта любого статуса; неподписанная строка отбрасывает предложение и печатается оператору как «the signed». ⚠ **Формулировка круга 1 «ни одна проверка не говорит ни слова» ОПРОВЕРГНУТА кругом 4 и снята:** дроп ЛОГИРУЕТСЯ (`gatherBankInputs` → `seeding.go`), но текстом «held by a **signed** term» каким бы ни был статус держателя, — то есть оператору говорят НЕВЕРНОЕ, а не ничего, и это ровно предмет позиции. ⚠ **Атрибутирую, а не присваиваю: своим прогоном исходный случай я не воспроизвела** — моя фикстура на `since_ch: 0` дала РАЗНЫЕ кортежи (обе строки легли, обе проверки сработали: `BankConflicts=1`, collapse=1, merge=1), а вторая итерация упёрлась в гейт пере-оплаты, потому что переиспользовала тот же проект. Проверено мной только по коду: `held` в `loadAutoBank` строится из параметра, которым передаётся `in.entries` (`bankmaterialize.go:125`), то есть из строк ЛЮБОГО статуса. 2. **`terminology.go:873` и `:941`** — обе канон-проверки пропускают пару с РАВНЫМИ источниками. Проверочную половину закрыл сегодня; **якорная осталась: роль не показывают, как книга уже зовёт поверхность, которую её просят перевести.** Это меняет содержимое запроса ⇒ хеш ⇒ деньги, в пак не входит. 3. **`terminologist.go:257` против `mining.go:553`** — фильтр «поверхность уже в банке» стоит только на ЭМИССИИ. Роль и классификатор ОПЛАЧИВАЮТСЯ за поверхности, которые банк уже несёт. 4. **`bankmaterialize.go:139-141`** — комментарий на вызове говорит «two DIFFERENT approved terms», тогда как `ApprovedSharedKeyCollisions` собственной докой заявляет, что same-src пары не пропускает. 5. **`mempostcheck.go:91` против `:122` и `:130`** — дока `Shown` говорит «how many unsigned rows were actually PUT IN FRONT of the model here», а sticky-перенос `continue`-ится ДО счётчика. Имя метрики шире её смысла. 6. **`internal/pipeline/bankmaterialize.go:132`** — remark оператору «auto-bank rows dropped: their key is already held by a **signed** term (the signed term wins)». Та же ложь, что в `loadAutoBank`: держателем ключа может быть неподписанная строка, и оператор увидит её названной подписанной. 7. **`internal/membank/memseed.go`, пропуск по UNIQUE-кортежу** — сид-строка с окном ПО УМОЛЧАНИЮ и без sense делит кортеж с banknote-предложением (у обоих `since_ch 0`), поэтому самая частая форма рукописной сид-строки против выработки роли **молчит**, каким бы ни был её статус. Замер круга 2: та же фикстура без `until_ch: 20` → `BankConflicts=0` и при `draft`, и при `approved`; с `until_ch: 20` → 1. На провод это не влияет (предложение отбрасывается, двух форм там нет) — теряется строка на ЛИСТЕ ПОДПИСИ. Закрытие требует правила «заменённая строка движка против отброшенного предложения», а колонка `Source` его не даёт: дельта владельца и авто-банк движка обе читаются `mined`. 8. **Пины на операторские сообщения есть, но узкие и несистемные** — носитель `internal/pipeline/seeding.go:73`. Текст варнинга S14 был закрыт ПОДСТРОКОЙ в `pipeline.TestUnsignedConflictIsReportedByTheRun`, и расширение правила его честно покраснило; но подстрока стерегла одно словосочетание из всего сообщения, поэтому локализующая половина (обе строки, оба окна, firing-ключ) не была закрыта ничем и появилась только этим паком. ⚠ **Прежняя формулировка этой позиции («не был закрыт ни одним тестом, `grep` = 0») была НЕВЕРНА и снята приёмкой:** греп искал целую фразу, живущую только в самом `seeding.go`. Класс остаётся, но он про ПОЛНОТУ пина на текст, а не про его отсутствие. 9. **`internal/terminology/terminology.go:993` и `internal/pipeline/mining.go:451` — ШОВ-БЛИЗНЕЦ того, что бил меня три круга, живёт рядом и НЕ ЗАПИНЕН.** Поля `Contradictions` и `Conf` пересекают границу файла тем же способом: ключ выбирается по разу с каждой стороны (`Contradictions` — по `c.Src` у писателя и читателя, `Conf` — по `c.Key` у обоих). Сегодня стороны согласованы, но ни одна фикстура не имеет кандидата с `Key != Src`, поэтому мутация любого из трёх ключей переживает ПОЛНЫЕ пакеты `pipeline`, `terminology` и `tmctl` (замер круга 6). На проводе не меняется ничего — теряются метка `⚠ contradicts` и порядок «least sure first» на листе подписи у banknote-кандидатов с традиционным/кана-написанием. ⚠ **Строки паком не тронуты, это не регресс**; свой шов я убрала целиком (§4-секстус п.1), а этот выношу, потому что он того же класса и чинится десятью строками рядом с существующим тестом. 10. **`internal/store/chunkstatus.go` вместе с `internal/pipeline/waverun.go` — ПУТЬ ЗАПИСИ СТАТУСА НЕ ЧИТАЕТСЯ ПО КОДУ, и это свойство места, а не невнимательность автора.** Писателей скипнутой строки ДВА, и какой сработает, решает раскладка волны: `recordSkippedStages` (`waverun.go`) — для флагнутой РЕДАКТОРСКОЙ единицы, флагнутая ветка `runStageSequence` (там же) — когда в ОДНОЙ волне две и более стадии. Читающий `chunkstatus.go` не видит ни того, ни другого. Замер: три формулировки механизма подряд оказались неверными (в дереве до пака, в моей первой правке, в моей второй), и каждую поймала только мутация — прочитанная по тексту, а не по цвету. #### 9. Правки существующих тестов, вызванные ЗАКАЗАННОЙ сменой поведения (`D39.183`) Расширение `UnverifiedKeyConflicts` заказано оркестратором (П1), поэтому два теста, описывавших прежнее поведение, — обслуживание, а не подгонка. Оба объявляю: 1. **`membank.TestUnverifiedKeyConflicts`** утверждал `len(got) != 1`. Теперь **2**, и второе нашлось В ЕГО ЖЕ ФИКСТУРЕ, лежащей в дереве с написания: `draft «старейшина»` против `auto «глава клана»` — пара неподписанных, которую никто не видел. Прежняя гарантия сохранена дословно; добавлены обе подписи, оба окна и firing-ключ в каждом сообщении, исключение approved×approved с контролем, «пара с двумя ключами — одна поимка». 2. **`pipeline.TestUnsignedConflictIsReportedByTheRun`** утверждал подстроку `"contradicts an approved term"`, которую расширение сделало ложной. Заменён на новый текст правила плюс требование локализовать неисправность: раньше проверялись две подстроки, теперь пять. **Куда уехала гарантия:** «прибор видит противоречие с участием подписи» → «прибор видит любое противоречие, кроме двух подписанных, и называет обе строки так, что оператор может их найти». Третья правка — `bankfixpack_test.go`, ассерт на текст варнинга схлопывания: текст пере-формулирован по находке круга 1 («DISAGREES with a row the bank already holds» вместо «contradicts…»), потому что прежняя формулировка обещала две формы на проводе там, где эмиссия предложение роняет. #### 10. Что НЕ удалось · что не проверено · где не хватило данных - **НЕ измерено, производит ли обычная последовательность операций состояние строки 267.** Замерена ДОСТИЖИМОСТЬ и предъявлено, что провода её несут; на живом прогоне не наблюдалось — пак $0. - **Корпусный ноль — про корпус, не про мир.** 142 книги — почти целиком одна книга в множестве прогонов. - **Не мерил объём вывода при массовом срабатывании:** маркер листа подписи предъявлен на фикстуре в 3 кандидата. - **Якорная половина находки §5а №2 не закрыта** (роли не показывают существующую форму) — меняет запрос ⇒ деньги. - **Двойной репорт не подавлен** — назван и вынесен решением оркестратора. - **Вопрос §4.1(в) «варнинг → стоп» не решал** (по промту пинг; оркестратор развёл «видеть» и «делать» по уровням и завёл строку бэклога). - **Чужие зоны:** в дереве параллельно правится `platform/` — не трогал; при лендинге коммитить только `backend/` pathspec-формой. #### 11. Что я сам считаю слабым местом 1. **Три круга самопроверки нашли 31 находку В МОЕЙ РАБОТЕ.** Пять — ложные утверждения в комментариях, то есть ровно тот дефект, который пак чинил; `chunkstatus.go` я написала неверно ТРИЖДЫ подряд (сначала «резюм не пишет», потом верное «пишет» с неверным механизмом, потом со вторым неверным), и каждый раз ловила только мутация, прочитанная по ТЕКСТУ. Вывод для приёмки: мои утверждения о поведении надо проверять исполнением так же, как чужие. ⛔ **И отдельно самое неприятное: одну находку внесла МОЯ ЖЕ ПРАВКА ПО НАХОДКЕ** — фикс круга 2 был верен в функции и сломал доставку этажом выше, потому что я запинила изменённую функцию, а не путь до потребителя. Правка по ревью — такой же новый код, как всякий другой. 2. **`ConsolidationKeyConflicts` и расширенная `UnverifiedKeyConflicts` частично перекрываются**, и это теперь ИЗМЕРЕНО (§4 п.7), а не предположено. Довод в пользу двух мест реальный (разные популяции), но «одно знание — один носитель» соблюдено не идеально. 3. ⛔ **Мой довод про UNIQUE был ЛОЖЕН, и выяснилось это только на круге 2 — прогоном, которого я на круге 1 не сделала.** Я сослалась на схему вместо того, чтобы её спросить; схема ответила иначе (ключ сырой, трад/упрощённая пара — две законные строки, обе инжектятся). Урок шире места: формула «доказано схемой» стояла в моём отчёте там, где честно было «не мерено». 4. **Мой e2e-тест обходил дыру подобранным значением:** `until_ch: 20` уводит сид-строку с кортежа предложения, без него проверка молчит (§5а №7). Это тот же класс, что «тест утверждает не то, что думает», и вынести подобранное окно должна была я, а вынес круг 2. Плюс маркер предъявлен на кандидате, которого в подписном документе НЕТ (`方源` — сид-поверхность): адрес верный (стоп-таблица содержит всех кандидатов), но случай «противоречие у термина, который владелец реально подписывает» отдельным тестом не покрыт. 5. **Комментарий в `waverun.go` цитирует ЧУЖОЙ замер** (1962/2283, строка 321). Не воспроизводил — атрибутировал. 6. **Три из девяти пунктов §5а — про `terminology`/`mining`, куда пак не посылал.** Их количество говорит, что класс «описание шире/уже поведения» в этих файлах не разобран, а я прошёл по касательной. #### 11-бис. Дерево на момент сдачи `git status --short -- backend/ docs/PROGRESS.md` (позиций по `backend/` — **18**: 16 M + 2 новых): ``` M backend/cmd/tmctl/render.go M backend/cmd/tmctl/render_test.go M backend/internal/membank/mempostcheck.go M backend/internal/membank/mempostcheck_test.go M backend/internal/membank/memseed.go M backend/internal/membank/memseed_test.go M backend/internal/pipeline/bankfixpack_test.go M backend/internal/pipeline/disposition.go M backend/internal/pipeline/export.go M backend/internal/pipeline/mining.go M backend/internal/pipeline/miningstop_join_test.go M backend/internal/pipeline/seeding.go M backend/internal/pipeline/terminologist.go M backend/internal/pipeline/waverun.go M backend/internal/store/chunkstatus.go M backend/internal/text/norm_test.go M docs/PROGRESS.md ?? backend/internal/pipeline/bankconflict_corpus_test.go ?? backend/internal/pipeline/resume_updatedat_test.go ``` Индекс пуст (`git diff --cached --name-only` → пусто). Чужого в списке нет: параллельно правится `platform/` — не моя зона, не трогала. **Не коммичу** — лендит оркестратор, pathspec-формой по `backend/` и моей секции журнала. Батарея снята ПОСЛЕ последней правки, и это предъявлено, а не заявлено: `find backend -name '*.go' -newer <лог батареи>` → **0**; КОНТРОЛЬ `find … -newer <маркер часовой давности>` → **5**. #### 11-тер. Заявление о завершённости **Работа завершена, править больше не планирую.** Критерий проверяется механически: 1. **Исход у каждого пункта заказа** — таблица §0, пунктов без исхода нет. 2. **Круги сошлись, и приёмка добавила три пункта дофикса — все закрыты** (§4-октавус). Круг 6 дал «сошлись»; всё найденное кругами 1–6 и приёмкой закрыто поимённо таблицей §4-тер. Два остатка круга 6 не в коде пака: пред-существующий шов-близнец вынесен §5а №10, счётчики пере-сняты. 3. **Числа сняты после последней правки, каждое командой.** Батарея `MAKE_EXIT=0` (19 пакетов `ok`, 0 красных, линтер `0 issues.`, 4 названных скипа); что она позже последнего касания кода — предъявлено: `find backend -name '*.go' -newer <лог>` → **0** при контроле **3**, и с тех пор изменён только `docs/PROGRESS.md`. 4. **Мутации** — таблица §5 полна (**23** строк), выжившие названы отдельной таблицей «зелено ДО → красно ПОСЛЕ», отброшенная названа с причиной. 5. **Обещаний в отчёте нет** — всё, что «надо бы», стоит секцией предложений ниже и решается оркестратором. 6. **Всё живое в дереве** — отчёт, таблицы, замеры, ограничения; письма носителем не считаю. 7. **Дерево в безопасной точке** — только моя зона, индекс пуст, не закоммичено, статус приложен выше. #### 12. Предложения (решает оркестратор, в паке НЕ сделано) 1. Подавлять ли повторный репорт пары на ре-сиде в авто-режиме (§4 п.7). Резать надо слияние, не схлопывание. 2. Показывать роли существующую форму поверхности (§5а №2, якорная половина) — меняет запрос и деньги. 3. Фильтровать кандидатов роли по банк-поверхностям (§5а №3) — снимает оплату за уже банкованные термины. 4. Ставить пины на ТЕКСТЫ операторских сообщений (§5а №8) — сегодня их нет системно, и расширение правила сделало один из них ложным при полностью зелёной батарее. 5. Запинить шов-близнец `Contradictions`/`Conf` (§5а №10) — десять строк рядом с существующим тестом, фикстура с кандидатом `Key != Src`. Мой собственный такой же шов ловился ТРИ круга подряд, и это единственная причина, по которой я его называю: цена дыры измерена на себе. 6. Довести разногласие до листа подписи и на форме сид-строки по умолчанию (§5а №7). Требует правила «заменённая строка движка против отброшенного предложения»; колонка `Source` его не даёт, потому что дельта владельца и авто-банк движка обе читаются `mined`. Это самая частая форма сид-строки, так что цена молчания не маргинальна. ⚠ **ПИНГ ОРКЕСТРАТОРА 06.09 — мелочь, у которой не было носителя, и потому она здесь.** `backend/internal/bookfile/model.go:59` разросся до **183 знаков** — единственная строка длиннее 120 в файле; удлинил её текст комментария, заландженный `f1e9226`. Правка на строку, линтер молчит, срочности нет. **Записано потому, что моё решение «поправит зона при следующем касании» само носителя не имело, а следующего касания может не быть годами** — и это ровно тот класс, который смена 06.09 ловила пять раз (находка, живущая только в письме). Возьми при любом касании файла; отдельного захода не стоит. ✅ **ПИНГ ОРКЕСТРАТОРА №22 от 05.09 про якоря — ИСЧЕРПАН В ТОТ ЖЕ ДЕНЬ, работать по нему НЕ НАДО.** Зона починила всё коммитом `e7d6b3f`: `counts.py --lint` → **0 битых якорей**, сверяемых по токену стало 200. ⚠ И нашла БОЛЬШЕ, чем было в пинге: из шести битых ПЯТЬ оказались старше её пака — их скрывало то, что `backend/docs` добавили в корни линта только 04.09; чей это дрейф, предъявлено замером, иначе пять чужих долгов записались бы ей. ⚠ Номера строк, продиктованные пингом, были НЕВЕРНЫ — зона пере-нацелила по СОДЕРЖИМОМУ и перевела ссылку в токенную форму, чтобы дальше её сторожил линт, а не человек. ⛔ **Что из этого стоит дороже починки — норма, найденная зоной у себя:** она гоняла СВОЮ проверку якорей после каждого касания кода и ни разу не прогнала гейт, который уже стоит в репозитории. **Два множества якорей и одна привычка — та, которую завела сама.** Разбор — `D39.202` п.3-бис. > **Состояние зоны на 05.09 (вечер):** активного промта НЕТ — пак «денежный стоп» ОТРАБОТАН и ПРИНЯТ С ДОФИКСОМ (акт **D39.206**, `81a89e9` + `616a8e4`), промт в `archive/prompts/` с баннером исхода; дерево `backend/` чисто. Следующая работа зоны — строки **291** · **294** · **296**. Прежняя редакция («на 31.08 активного промта нет, дерево чисто») читалась как текущее и приглашала следующего править чужое дерево. Ратифицированные лендинги > зоны: входная дверь шва — **D39.158** (`d1eb8a9`) · «тихая порча» — **D39.164** (`7d0c6f2`) · «деньги» — > **D39.170** · гейт схемы — **D39.173** · «писатель книги» — **D39.175** (`8adcb86`) · «деньги и честность > выдачи» — **D39.182** (`bb541a8`) · ЗАКОН РАСКРЫТИЯ, ратифицирован владельцем — **D39.181** · четыре > строки бэклога закрыты тем же лендингом — **D39.185**. Диспозиция по D25.1 ратифицирована D39.175 п.2 > (drift — не дыра файла; лестница — владельцу между паком и дверью). > > **Свободная работа зоны — строками бэклога:** ~~**246**~~ (ЗАКРЫТА 04.09 актом D39.194 — копия потребителя приведена к производителю) · > **247** · **232** · **233** · **197** (ресурс ушёл в фазу 1, строка не взята) · **228** · **229** · **230** · > **141**-остаток · **131**. ⚠ Строк 231 и 236 в таблице БОЛЬШЕ НЕТ — 231 съел пак «деньги», 236 сужена D39.175. > > ⚠ **Прожитая проза зоны за 24–31.08 СНЯТА отсюда** — история живёт слайсом > [archive/PROGRESS-2026-08-backend.md](archive/PROGRESS-2026-08-backend.md) и телами нот выше; читать её > не надо. Доказательная база пака «деньги и честность» и ВСЕ его пинги — файлами зоны: > `backend/docs/MONEY_HONESTY_REPORT.md` (§7 — пинги оркестратору, §9 — экземпляры закона по одному, > §0.1 — батарея ИСПОЛНЕНИЕМ, **§5.1 — разложение покупок П1/П2/П3**: ось пере-покупки терминолога = > БАЙТЫ БАТЧА, а не сдвиг снапшота — это и есть «пинг №2», которым D39.185 п.1 адресует сюда; §6.2 — > адверсариальный проход), `backend/docs/DISCLOSURE_LAW_DESIGN.md`, `backend/docs/MONEY_HONESTY_PLAN-NOTE.md`; > промт — `archive/prompts/BACKEND_MONEY_HONESTY_SESSION_PROMPT.md`. ### 05.09 — ОТЧЁТ пака «ФОРМАТЫ И ЧЕСТНЫЙ СЛОВАРЬ» (сессия `textmachine-main-fe`, промт `CHAPTER_STRUCTURE_SESSION_PROMPT.md`) **Полный отчёт — `backend/docs/CHAPTER_STRUCTURE_REPORT.md`.** Здесь только несущее. Денег $0. **Гейт §3 взят по ветке (а) на ВОСЬМИ исходниках из восьми:** id глав и номера байт-в-байт, `structure` не изменился. Двинулось ровно заказанное — `key` и сегмент `cutTag` внутри unit-id при неподвижном префиксе id главы (`c3aa4cbbb53de134:d4fb75e2:0` → `c3aa4cbbb53de134:1b30b1dd:0`). Батарея: `make battery` EXIT 0, 19 пакетов, 0 FAIL, линтер 0 issues, скипов 3 — те же три, что и до правок. **Построено:** данные структуры ИСТОЧНИКА со своим загрузчиком и лестницей (файл языка → CJK-дефолт по скрипту → честный `none`) · компонент `Structure` в `cutInputs` и в ключе манифеста · четвёртое значение `delimited` и КОНКУРЕНЦИЯ свидетелей вместо сложения · EPUB `nav`/NCX с правилами прикрепления и счётами · `title_raw` аддитивно · бамп `chunkerVersion` v6→v7 с пере-захватом голдена. ⛔ **Дрейф ingest↔chunker был ЖИВОЙ, а не гипотетический** (замерено до кода): ингест резал по пяти юнитам `章节節回話` из embedded `cjk-section.txt`, чанкер — по четырём `章节節回` из пар-файла, и комментарий `ingest.go`, утверждавший «ONE source, no ingest↔chunker byte-drift», описывал намерение, а не код. Пак его ЗАКРЫЛ, а не предотвратил: `cjk-section.txt` не тронут ни строкой, чанкер начал читать ЕГО. ⛔ **ГЛАВНОЕ, ЧТО СТОИТ ДОРОЖЕ КОДА — заказ содержал ЦИКЛ, и существующий тест его не ловил.** Решить «есть ли шапки» нельзя до нейтрализации `\f`: шапка сразу за ним лежит на ОДНОЙ строке с прозой предыдущей главы и отвергается двумя предикатами сразу. При наивном порядке глава теряется МОЛЧА, а `doc.Structure` остаётся ВЕРНЫМ — то есть тест, проверяющий только ярлык, проходит над потерей. Класс `D39.205`. Предъявлено посадкой: наивный порядок красит `TestTXTHeaderRightAfterAFormFeedIsNotLost` («chapters = 2, want 3»), а тест провенанса при этом ЗЕЛЁН. ⚠ **Шесть находок до кода, все приняты и внесены в промт** (`24f02bb` · `23b00a3` · `5a502e7` · `cd55329`). Кроме цикла и дрейфа: гейт был недостижим по построению (требовал байт-в-байт манифест, а пак сам заказывает сдвиг `cutTag`); `langpack_root` 20 конфигов из 31 указывает в дерево ветки `polygon`; **стенд отстал от движка — стенд-конфиг даёт манифест ровно для 1 исходника из 8** (`{{genre}}` ретирован и жив в шести промтах polygon, `mined_delta`/`mined_rejects` — в 17 конфигах из 31, поля `stm_depth`/`overlap_tokens` исчезли). ⚠ **Норма, купленная сменой трижды за день: счёт по ИМЕНИ и счёт по СОДЕРЖИМОМУ — разные замеры, и первый молча даёт зелень.** Шапки книги уникальны, а НОМЕРА повторяются шестикратно (первый прогон дал «повторов 0» и был неверен); файлы разноимённы, а байты те же (исходников восемь, не девять). Меряй хешем, не basename. ⚠ **Выжившая посадка, записанная с аргументом:** переворот сортировки целей `nav` не покрасил ничего — `starts` читается как МНОЖЕСТВО, группировка идёт по spine. Комментарий поправлен на правду вместо красивого утверждения; сортировка оставлена как контракт поля, а не как несущее свойство. ⛔ **Схлопнутые цели `nav` понижают провенанс до `delimited`** (правка спеки, найденная сдачей): книга, пакующая несколько глав в один документ с якорями, объявляет больше глав, чем пак отдаёт, и назвать такой разрез `declared` значило бы выдать своё, более грубое, за слово формата — та же ложь, что говорил spine. Четырёхзначного словаря хватило, достраивать ничего не пришлось. Резка по якорям в пак не входит. **Ревью-вопрос проекта закрыт ИСПОЛНЕНИЕМ:** `TestANewLanguageCutsFromItsDataFileAlone` — корейская книга без своего файла остаётся ОДНОЙ главой, с `ko/structure.txt` режется на ТРИ и несёт `title_raw`; один бинарь, один текст, разница только в файле данных. **Каталог мутаций 201 → 205.** Две записи целили в предикаты, которые §1 приказал УДАЛИТЬ, и пере-нацелены на свойства, занявшие их место; три новые — на правила формата. Все шесть прогнаны: 6 RED, 0 неожиданных. ⚠ Полный прогон 201 записи НЕ делался (124 из них гоняют `./internal/pipeline/` по ~145 с); вместо него механически проверено, что у всех 205 записей цель ЖИВА. **ДОФИКС ПО ПРИЁМКЕ 06.09 — шесть обязательных находок, все подтверждены мной заново и все закрыты.** Дороже прочих **M-1: молчаливая потеря текста.** Роль `toc`/`cover`, объявленная С ФРАГМЕНТОМ (`href="c2.xhtml#pos"`), исключала ВЕСЬ документ — а фрагмент значит «оглавление НАЧИНАЕТСЯ здесь внутри», а не «файл целиком служебный». Проза исчезала при уверенном ярлыке `declared` и молчащем логе. ⛔ **Форма уже стоит в EPUB владельца:** у Kristoff `type="toc" href="index_split_124.html#filepos2096584"`, и мой прогон после починки показывает там `service_roles_inside_documents 1` — то есть ровно этот случай на живой книге. ⛔ **M-2: тревога не приходила никуда.** Из пяти счётов логировались два; 126 документов, схлопнутых в 6 глав-китов, печатали в stderr **ноль байт**. Починено не пятью вызовами, а ОДНИМ репортёром `IngestNotes()` и рефлексионным сторожем, который краснеет на любом новом неподключённом счётчике: пять мест — это пять шансов забыть шестой. ⚠ **Замер EPUB владельца через новый путь (мой, не верификатора):** Kristoff — 71 глава `declared`, из них **64 короче 200 знаков** (min 18, медиана 29, max 397 878); isekai — 44 главы, 9 коротких; fifty_shades — 32 главы, 3 коротких. `title_raw` заполнен у 71/71, 44/44 и 32/32. ⛔ Цена Kristoff названа: 64 единицы манифеста несут не текст книги, а строки заднего листинга, и пойдут в оплату как главы — вопрос владельца. ⚠ **Объявление D39.183, замеренное:** регэксп ингеста стал допускать пробел между маркером и цифрой, чтобы ингест и чанкер читали заголовок одинаково. Разница на всех стендовых файлах — **ноль** (蛊真人 2996→2996, голден 8→8, оба ja-txt без изменений). ⚠ **Находка о СВОЁМ коде из дофикса:** прежний `resolveHref` раскодировал href ДО среза фрагмента, значит литеральный `#` в имени файла (приезжающий как `%23`) обрезал имя. Два почти-дубля резолвера сравнивались друг с другом и расходились молча — «один источник на факт» я заказывал сам и сам же не выдержал. Сведены. Каталог 205 → **210**, пять новых прогнаны: 5 RED, 0 неожиданных. ### 04.09 — ОТЧЁТ вайр-батча «род · экран цели · заголовки инъекций» (сессия `textmachine-main-7e`, промт `BACKEND_WIREBATCH_SESSION_PROMPT.md`) > **ПЕРВОЙ СТРОКОЙ, потому что промт этого требует: `internal/lang/data/` НЕ ТРОНУТ НИ БАЙТОМ.** Пункт 3 сделан снятием РЕНДЕРА в Go. Предъявление, а не утверждение: `diff -r <(git archive HEAD backend/internal/lang | tar -xO) …` идентично, и `tmctl manifest --json` из HEAD и из дерева на `example/book.yaml` дают ТОТ ЖЕ `manifest_key` `e996b9d4f129006e9faa6237fb1635a82e32c06c056b195072fae15f582021f6` и ТОТ ЖЕ `unit.id` `f8ad8c8f114997c5:3d2213f2:0` (средний сегмент — `cutTag`). ⇒ пере-чеканки `unit.id` нет, `recut` у платформы не сработает, `unit_resolutions` книги параллельного платного прогона целы. > > **Состояние: пять пунктов из шести закрыты, шестой (140) упёрся в факт развёртывания и вынесен решением оркестратору — см. §4.** Дерево НЕ закоммичено, лендинг за оркестратором. **Батарея (предусловие, не отчёт).** `cd backend && make battery` → `MAKE_EXIT=0`, `golangci-lint` `0 issues`, `ok` в 19 пакетах, SKIP три и те же: `TestMinerFullBookParity`, `TestHelperEventsRun`, `TestHelperKillLoop`. **Тесты.** `grep -rn '^func Test' backend --include=*_test.go | wc -l` → **1105 → 1143**, добавлено 39 (из них 10 — дофиксом приёмки). **Удалённых имён ОДНО, и оно названо:** `TestEditorSectionFollowsProvenance` — это ПЕРЕИМЕНОВАНИЕ, а не потеря. Его предмет (маршрутизация двух секций редактора по провенансу) упразднён пунктом 3 вместе с самими секциями; уцелевшая половина утверждения живёт под `TestTheGenderDirectiveAsksTheMatchAndTheWireAsksNothingElse` и стала СИЛЬНЕЕ — держит оба блока, а не один. Команда диффа: `comm -23 <(git show HEAD:… ) …` по пофамильным снимкам. **Каталог мутаций.** `python3 -c "import json;print(len(json.load(open('backend/cmd/tmmutate/mutations.json'))))"` → **92 → 105**. --- ## Пункт 1 — строка 210: род ПРОИЗВОДИТСЯ. ЗАКРЫТ, с честной границей доставки **Развилка выбрана ЧЕТВЁРТАЯ, которой в промте не было: род производит существующий фокус-проход КЛАССИФИКАТОРА** (`runClassifier`), третьим полем ответа. Довод: ноль новых вызовов (проход уже гоняется по тем же кандидатам с теми же контекстами) при цели №5 «низкий COGS»; род — свойство сущности, выводимое из контекстов, то есть акт классификатора, а не выбор рендеринга; парсер классификатора позиционный и закрыто-словарный, тогда как третье поле терминолога — уверенность, вокруг которой написана деликатная развязка мис-сплита по живому дефекту «наставник 95%». Цена: двигается `RequestHash` ТОЛЬКО классификаторных вызовов; терминологические чекпоинты книг живы. Ратифицировано оркестратором. **Построено.** Промпт пары `prompts/zh-ru/classifier.md` v2 — третье поле, закрытый словарь `male|female|neuter|none`. ⚠ `hidden` в словарь НЕ входит НАМЕРЕННО: «пол скрыт до раскрытия» — решение о сюжете и спойлерной политике книги, а не наблюдение по KWIC-строкам; ошибочная догадка де-гендерила бы обычного персонажа на всю книгу. Остаётся ручным, в сиде. `none` — полноценный ОТВЕТ, а не пропуск колонки: без слова для «рода нет» единственный способ это сказать — не писать колонку, что неотличимо от «модель перестала отвечать». Go: `terminology.Genders` + `ParseTypes` возвращает `types, genders, stats`; `ReplyStats.BadGender`/`NoGender` — два счётчика, потому что это два разных отказа; `pipeline.attachClassifiedGender`; `miner.Term.Gender` → `DeltaFile` → сид-YAML → сайдкары → банк. **Гарантия, которую держит тест:** колонка рода НИКОГДА не стоит классу — значение вне словаря отбрасывается и считается, класс сохраняется (`TestTheGenderColumnNeverCostsTheClass`). **⛔ ГЛАВНАЯ НАХОДКА ПАКА: ЗАМКОВ ТРИ, И НАЗВАННЫЙ В ПРОМТЕ — НЕ СВЯЗЫВАЮЩИЙ.** `bankmaterialize.go` держит ДВА банка: черновая волна выбирает по `baseMemory`, из которого строки `Source:"mined"` вычеркнуты ПО ПОСТРОЕНИЮ, редактор видит обогащённый. Авто-банк пишется как `mined` (`mining.go:671`), подписанная дельта — тоже (`mining.go:896`, дословно «override the seed loader's Source:seed → mined (base-excluded)»). ⇒ **на ЧЕРНОВОЙ провод произведённый род не едет и не поедет: там нет самой СТРОКИ.** Это не дефект — это денежный контракт `D39.42` п.3: инъекция черновой волны байт-стабильна поперёк обогащения банка, иначе пере-снапшот платит две волны вместо одной. Не трогал и не предлагаю. **Формулируй границу так и не короче:** род производится авто-путём и доезжает до РЕДАКТОРСКОГО провода в том же прогоне, что его произвёл; на ЧЕРНОВОЙ не едет, пока цена двух волн не решена отдельно. Не «род построен». **Второй замок СНЯТ по ратификации оркестратора, и снят РАСЩЕПЛЕНИЕМ, а не целиком.** `Disp` сворачивал два вопроса — СТАТУС строки и надёжность МАТЧА. `D39.104` п.1 упраздняет разнобой по статусу («банк на проводе = закон независимо от статуса строки»), но про матч там нет ни слова и быть не может: род, приписанный не той сущности, — ошибка, а не неподписанность. Заведено поле `PickedEntry.KeyTrusted` + тип `InjectionTrust{Disp, KeyTrusted}`, который несёт ОБА факта через липкое окно (у липкого переноса нет своего ключа, и матч-половину, как и диспозицию, восстановить нечем). Род теперь гейтится `KeyTrusted` на ОБОИХ блоках; статус не решает ничего. **Сквозное доказательство — три двери порознь, а не «работает»** (`internal/pipeline/gender_wire_test.go`): (1) неподписанная строка на доверенном ключе НЕСЁТ род редактору в том же прогоне; (2) collision-prone матч не несёт НИКУДА, при ЛЮБОМ статусе (юнит-проверка: на zh ветка не срабатывает физически, ханьские ключи якорятся на 2, поэтому сквозной zh-фикстурой её достать нельзя); (3) на черновой провод род не попадает НИКОГДА — и утверждение перевёрнуто нарочно: откроет кто-то дверь 3 — тест покраснеет и заставит автора назвать, какую именно. **Отрицательный контроль есть:** `TestASignedGenderBeatsTheProducedOne` — сид владельца побеждает, и не порядком присваивания, а тем, что `loadAutoBank` роняет предложение движка на занятый подписью ключ. Команда: `go test ./internal/pipeline/ -run 'Gender' -v`. ⚠ **Пункт 4 — ПРЕДПОСЫЛКА пункта 1 в бою.** Род производится только когда включён `classify_types`. Без банкового контура в боевом конфиге род не производится ни при каком варианте развилки. ## Пункт 2 — строки 113 → 46: база записана, экран построен. ЗАКРЫТ **113 — СТОП СНЯТ, все три порога пройдены.** Корпус взят исполнением: все чекпоинты всех 162 БД стенда, через СОБСТВЕННУЮ предобработку движка (`splitBanknote` → `checks.StripThink` — тот текст, который видит гейт), дедуп по хешу, только отгрузочные роли (банк-роли исключены: их ответы законно состоят из исходных термов, и включив их, мерили бы исключение, а не гейт). Обход дал **1162 ответа: 30 off-target, 1132 здоровых** — но ⚠ **в РЕПОЗИТОРИЙ уехала ВЫБОРКА, и все числа ниже воспроизводимы над ней, а не над обходом**: 74 строки, все 30 off-target плюс 44 ЗДОРОВЫХ, отобранных нарочно трудными (20 с высшей долей исходного письма, 15 с низшей долей целевого, 3 под полом улики, остальное — спред). Тексты в git не поехали, довод — в шапке `offtarget_corpus_test.go`. **Разметка НЕ гейтом, иначе она была бы пересказом вердикта:** off-target = доля КИРИЛЛИЧЕСКИХ букв < 0.5 — свойство ЦЕЛЕВОЙ стороны, независимое от проверяемого исходно-письменного гейта. Корпус разделяется полностью: здоровые все выше 0.9, off-target все ровно 0.0000, полоса между ними ПУСТА. **Числа воспроизведены и совпали с опубликованными до знака:** худший здоровый source-share **0.011655** (контракт называл 0.0117), запас **12.87×** против порога 0.15 (контракт называл 13×), **ноль ложных на 44 трудных здоровых** (не на 1132 — над репозиторием проверяемо именно это), поймано **28 из 30** (контракт называл 18 из 20 на более узком срезе того же стенда — та же доля, те же два промаха). Промахи — два беглых АНГЛИЙСКИХ черновика на **4690** и **4811** букв, ровно те, что названы в `EFFORT_HANDLE §3.1`. Худшая здоровая доля ЦЕЛЕВОГО письма **0.9767**, максимум у off-target **0.0000**, самый короткий off-target **346** букв — все три числа контракта воспроизведены. Команда: `go test ./internal/pipeline/ -run 'OffTargetCorpus|LiveEchoGate|LatinOffTarget' -v`. ⚠ **ЧЕГО ФИКСТУРА НЕ НЕСЁТ, и это мой выбор с ценой.** `testdata/offtarget-corpus.json` несёт РУНОСЧЁТ каждого образца (всего рун, рун исходного письма, букв, букв целевого письма), происхождение, метку и шестидесятирунную голову для человека — но не тексты. Тексты — копирайтная вебновелла и её машинные переводы, которые репозиторий держит вне git намеренно (стенд версионируется отдельным репо, `example/` возит собственный фрагмент по той же причине). Руносчёта достаточно ПО ПОСТРОЕНИЮ: обе проверяемые функции — отношения классов рун и ничего больше не читают, и тесты кормят НАСТОЯЩИЕ функции скрипт-верным суррогатом, собранным из счётчиков, а не считают арифметику вместо них. **Названная потеря:** детектор, который будет читать слова, n-граммы или орфографию, на этой фикстуре не измеряется — ему нужен повторный обход стенда. **46 — экран построен формой (а) плана §5.4 и заморозкой `D39.92`/`D39.93`.** Отдельный пакет чистых функций `internal/langscreen` (вход: текст + скрипты цели; выход: ИМЕНОВАННЫЙ вердикт `on_target|off_target|abstain` + счёт и объём улики). Порог `OnTargetFloor = 0.50` — КОНСТАНТА в пустом интервале, не тюнинг (гарантия Неймана–Пирсона на этом корпусе не покупается — `D39.92` п.1а); пол улики `MinLetters = 200` калиброван, а не выбран: самый короткий off-target 346 букв, ниже пола падают три здоровых. Носитель данных — `lang.LangScripts`, НОВОГО эмбед-файла не заведено. **Флаг СВОЙ — `FlagOffTargetLang`, `FlagCJKArtifact` НЕ переиспользован** (`D39.93` п.2), явный вход в `escalatable()`, не `retryable`. `classifierVersion` v2 → v3, и версия правила `langscreen.Version` вплетена в литерал, так что правка ВНУТРИ модуля двигает снапшот сама, а не по дисциплине. **Приёмочный критерий §5.4 шага 5 исполнен:** офлайн-прогон по корпусу — экран новооткрывает РОВНО два ответа, оба английские, здоровых не двигает ни одного (в тесте это `Fatal`, а не `Error`: план требует СТОП). Вдвоём два правила ловят **30/30 при нуле ложных**. Команды: `go test ./internal/langscreen/ -v` · `go test ./internal/pipeline/ -run 'TargetScreen|TwoScreens|BankRoleReply' -v`. **Вторая половина дыры закрыта тем же диффом:** `detectLatinInsertion` теперь под `c.TargetScriptNonLatin()` (`internal/checks/sanitizer.go`). Правило существовало в прозе доккоммента и стояло только на пути репэйра; первая же латинописьменная цель уронила бы КАЖДЫЙ чанк чистой целевой прозы как «Latin insertion». Для ru вердикты не двигаются ни на байт (предикат истинен) ⇒ бампа версии санитайзера не требуется. ⚠ **НАХОДКА, приехавшая ВМЕСТЕ с паком, а не до него.** Экран и эхо-гейт обязаны молчать на ответах банк-ролей: их буквы — движковые идентификаторы и исходные термы, поэтому эхо-гейт флагал бы их (и флагал: `verdict=cjk_artifact` при `bad_lines=0` на чистой пробе 6/6), а экран флагал бы ВТОРЫМ способом. Исключение было записано как `role == roleTerminologist` и КЛАССИФИКАТОРА не покрывало (`13-tech-debt-anchors §Б-105`) — латентно, пока ни один боевой конфиг классификатор не включал. Пункт 4 его включает. Поле переименовано в `NonProseReply` (оно про ФОРМУ ответа), предикат один — `isBankRole`, рядом со строкой, которую новая банк-роль и так обязана добавить в `bankRoleSettings`. ## Пункт 3 — строка 134: рендер снят, данные не тронуты. ЗАКРЫТ **Выбор объявлен: снят РЕНДЕР в Go.** Механизм, по которому выбор сделан: `cutTag` сворачивает `lang.EmbeddedVersion()`, `injection.txt` лежит в `internal/lang/data/` ⇒ правка данных пере-чеканила бы `unit.id` всей книги → `manifest_key` → снос `unit_resolutions` у платформы (строка 198). `RenderFormatVersion` в `cutTag` НЕ входит — он фолдится только в снапшот. Предъявление — первой строкой этого отчёта. **Текст заголовка не менялся вовсе,** и это проверено, а не принято на веру: действующий `editor_header` БАЙТ-ИДЕНТИЧЕН арму `AM-noclause` пробы 18 (`experiments/18-editor-wire-probe.md` §0.3 дословно: «Закон БЕЗ оговорки = действующий `editor_header` без единой правки»). Оговорка области НЕ внесена (опровергнута §A.4). **Что изменилось:** маркер ⟨проверить⟩ не рендерится НИ В ОДНОМ блоке; секция `editor_unverified_header` не рендерится, две секции редактора схлопнуты в один закон-блок; неподписанные строки стоят в нём под тем же заголовком и ничем не помечены. Статусы строк и подписная таблица не тронуты (`D39.104` п.1). `RenderFormatVersion` v3 → v4. **Ревью-ось «маркер снят, а пост-чек жив» проверена:** `membank.Postcheck` ключуется на `p.Disp`, маркера не читает — обработка `Ambiguous` цела, счётчики `Shown`/`Followed` живы. ⚠ Но их СМЫСЛ сузился, и это записано в код: они родились на проводе, который помечал строку и приглашал модель её отвергнуть; теперь неподписанная строка показана законом, отклонение — просто отклонение, а не «модель пользуется дарованным правом». Та же поправка внесена в доккоммент миграции v12, которая эти колонки завела. **Операторские тексты, которые стали бы ложью, переписаны** (не комментарии — то, что печатается человеку): две строки `tmctl` про «уедет к редактору с пометкой ⟨проверить⟩», строка `Unsigned bank terms` в `report`, WARN стопа майнинга, WARN конфликта с подписанным банком. ⚠ **НАХОДКА, которую я НЕ ЧИНИЛ и которая теперь висит на строке 250** (носитель заведён оркестратором): строка данных `ru glossary_header` САМА ОПИСЫВАЕТ снятый маркер («строки с пометкой ⟨проверить⟩ — неподтверждённые кандидаты»). После пака помеченных строк на проводе нет, а заголовок продолжает объяснять модели пометку. Это не мёртвая строка данных (`editor_unverified_header` и `unverified_marker` — те просто перестают читаться, и обе оставлены ОБЪЯВЛЕННЫМИ полями, потому что их СТРОКИ остаются в эмбеде, а `parseInjection` отвергает незнакомый ключ), а ЖИВАЯ строка с висячей ссылкой. Чинится только правкой `injection.txt`, то есть ценой `cutTag`. По `D39.104` п.1 клаузула становится ВАКУУМНОЙ, а не ложной; вред не измерен. ## Пункт 4 — строка 140: контур внесён в c1. ЗАКРЫТ с НАЗВАННЫМ предусловием развёртывания **Внесено в `configs/pipeline-c1.yaml`:** `gates.banknote.enabled: true` + `prompt_override: ../prompts/zh-ru/translator-banknote.md` на стадии draft со своим лейблом (`D39.10`: включение банкноты — ДВА согласованных изменения; сам гейт только СРЕЗАЕТ блок, инструкцию писать его несёт промпт) · `gates.terminology` (модель `deepseek-v4-flash`, `reasoning: low` — у рендер-фазы это вынужденно, на вендорском дефолте она сжигает бюджет размышлением и возвращает пустое тело) · `classify_types: true` · `mining.contrast_path`. **Суб-бюджеты — числа и их довод.** Множитель ×4.47 чинит пере-пин цен DeepSeek и ТОЛЬКО его; прежние 0.05/0.02 размерены под десятиглавую пробу, а этот файл обслуживает книги целиком. Замер (строка 16, десять глав, июльские деньги ×4.47): терминолог **$0.0257**, классификатор **$0.0344**. Бюджеты КНИГО-ШИРОКИЕ и копятся по всем прогонам книги (`store.RoleSpentUSD` суммирует чекпоинты роли по всем её джобам), а кандидатное пространство терминолога зависит от того, какие чанки уже отчерновлены, — значит между покупками оно меняется, `request_hash` другой, и книга, проданная десятью покупками, платит десять книжных консолидаций. Пол ⇒ **0.257 / 0.344**. Взято **1.00 / 1.00**, запас **3.9× / 2.9×**. ⚠ **Первая редакция дала классификатору 0.50, то есть запас 1.45×, а комментарий рядом обещал «≈3×» — число одной величины под именем другой. Поймано МОИМ ЖЕ адверсариальным проходом, исправлено: по замеру классификатор ДОРОЖЕ рендера, и «половина» пришла из старых чисел, а не из измерения.** Бюджеты остаются раздельными при равных значениях: разделение про то, чтобы перерасход одной фазы не голодал другую. Пин: `TestTheBankRoleBudgetsClearTheirMeasuredCost` — это ПОЛ, а не значение; поднимать можно свободно, опускать ниже замеренного нельзя. **⛔ ПРЕДУСЛОВИЕ РАЗВЁРТЫВАНИЯ, названное вслух: `mining.contrast_path` — единственный вход контура, которого нет в git.** ОБА банк-роля живут ВНУТРИ стопа майнинга, и `runBankMiningStop` возвращается РАНЬШЕ построения хоть одного кандидата без корпуса контраста. Артефакт (jieba-словарь общей частотности, 5 МБ) под `.gitignore` намеренно, но ВОСПРОИЗВОДИМ — рецепт и sha256 запинены в `docs/experiments/16-bank-mining.md`. Носитель требования к рантбуку и слово оператора — строка **251** (заведена оркестратором). **Два гарда, которые делают «настроено и мертво» невозможным** — и оба нашлись не по заказу, а по разбору: 1. Загрузка отказывает, если гейт включён, а `mining.contrast_path` ПУСТ (`internal/config/pipeline.go`) — тот же класс «гейт, который не может выстрелить», который лоадер ловит везде. 2. Наличие ФАЙЛА проверяется на ПИШУЩЕМ пути, рядом с `CheckKeys` (`Pipeline.CheckMiningContrast`, вызов в `openRunner` внутри `forWrite`). Место выбрано не случайно: `os.Open` внутри прогона стоит ПОСЛЕ оплаченной черновой волны, то есть развёртывание, забывшее артефакт, платило бы за волну, чтобы это узнать. $0-поверхности не трогаются (`D20.4`). 3. ⚠ **ТРЕТИЙ гард добавлен по находке адверсариального прохода, и он закрывает дыру в моих же первых двух.** У раннего возврата ДВА условия, и я гейтил только одно: `r.pack == nil` — а нил-пак книга получает, если не объявила `langpack_root` вовсе или объявила корень без каталога своей пары («nil-and-run»). Такая книга могла нести полностью настроенный и забюджетированный контур и не исполнить из него ни строки. Конфиг-лоадер этого структурно не видит: гейт знает пайплайн, пак знает книга, и вместе они есть только в раннере. Отказ добавлен там, тоже только на пишущем пути. ## Пункт 5 — строка 184(а): жанр выкинут. ЗАКРЫТ `grep -rl '{{genre}}' backend/prompts/ | wc -l` → **6 → 0**. Поле снято из канона брифа (`BriefHash`), `{{genre}}` снят из плейсхолдеров `pipeline.Render` — значит промпт-пакет пары, написанный позже с этим маркером, падает ГРОМКО на первом рендере, а не подставляет пустоту. Репо-гейт на ту же вещь: `TestNoShippingPromptAsksForTheGenre`. **`BriefHash` двинулся у ВСЕХ книг** (`c2021b1b…` → `4624529b…` на голден-фикстуре) — это заказано `D39.138` п.2в и внесено в общее окно пере-снапшота именно потому, что платится один раз со всем батчем. ⚠ **Ключ `genre:` ОСТАВЛЕН ПРИНИМАЕМЫМ, и это не мягкость.** Платформа пишет книге `book.yaml` ОДИН раз из шаблона оператора и никогда не перезаписывает, протаскивая незнакомые ключи насквозь — `genre` там назван явно (`platform/deploy/README.md`). Декодер движка строгий (`KnownFields`), поэтому удаление поля отказало бы в загрузке книгам, которые уже лежат на диске, посреди живого прогона соседней сессии. Идиома — та же, что у ретированного `adult: false`. Значение не читается ничем: `TestARetiredGenreKeyStillLoadsAndReachesNothing` держит и загрузку, и равенство `BriefHash` у двух книг, отличающихся только жанром. ⚠ Лейблы промптов бампнуты и леджер пере-записан (`v1-reflow` → `v2-reflow-nogenre`, `v3-discourse-reflow` → `v4-discourse-reflow-nogenre`): байты промптов уехали, а лейбл обязан следовать за ними — иначе два прогона под одним лейблом несравнимы, что этот гейт и ловит. **Тем же касанием в свип леджера добавлен КЛАССИФИКАТОР:** он был вне его, пока ни один боевой конфиг его не включал, а его промпт решает КЛАСС термина, то есть маршрутизирует имя в транскрипцию, а реалию в перевод. ⚠ `genre: ранобэ` НАМЕРЕННО оставлен в `testdata/golden/book.yaml` с комментарием «не прибирать»: это место, где терпимость к ретированному ключу упражняется на каждом захвате. ## Пункт 6 — дофикс чужого пака + ФЧ-7. ЗАКРЫТ ⚠ **Это остаток ЧУЖОГО наряда (`D39.187` п.4), а не мой заказ** — сессия, делавшая тот пак, не пережила рестарт окружения. **(а) Развилка операторской строки прибита со ВТОРОЙ стороны.** Воспроизвёл сам: ДВЕ посадки в новый код `VolumeStop.String()` переживали всё дерево (проверено с `GOFLAGS=-buildvcs=false`, иначе `cmd/tmctl` падает на VCS-штампе копии и маскирует результат) — (1) развилка заголовка всегда истинна, (2) развилка заголовка спрошена про ПЕРЕНОС вместо ОСТАТКА. Обе печатают в смешанном состоянии «reached the END of the book … Still in the book: 1 unit(s) NEVER delivered». Прибито `TestTheStopLineSaysTheGrantHeldWorkBackWhenItDid` — таблицей из ДВУХ строк, потому что две потери теряются на разных состояниях: всегда-истинная падает на любой, а спрошенная-про-перенос только там, где перенос и остаток оба ненулевые. Записи каталога `WB1`, `WB2`. **(б) Граница `bound()` прибита.** `Carried > 0` → `Carried > 1` переживало: существующий тест переносит ДВА юнита. Прогон с ОДНИМ перенесённым на конце книги не отдавал отчёт вовсе — тихий лимит, анти-паттерн `D39.165` §1б. `TestOneCarriedUnitIsStillWorkOutsideTheGrant`, запись `WB3`. **(в) Три числа отчёта — ПРОВЕРЕНЫ И СХОДЯТСЯ на HEAD.** `D39.187` п.4(в) говорит «протухли снова»; пере-снял все три их собственными командами до своей работы: батарея `EXIT=0` с теми же тремя скипами · `^func Test` **1105** · каталог **92**. Отчёт 03.09 называет 1105 и 92. ⇒ пункт (в) закрыт лендингом `f8d3e9a`, и остатка по нему нет. **ФЧ-7 — ВОСПРОИЗВЕДЁН и ПОЧИНЕН. Починка СВЕРХ заказа, объявляю.** Промт заказывал проверку исполнением и починку только при воспроизведении. Первая попытка воспроизведения ПРОВАЛИЛАСЬ и это важно: после потолка фидер `runWave` перестаёт раздавать элементы, поэтому второй воркер паниковать не успевает. Нужна синхронизация, чтобы обе позиции были в полёте, — и тогда воспроизводится ровно как описано: `runWave` отдавал ТОЛЬКО панику, `errors.As(err, &CeilingHalt)` → false, `errors.Is(err, errReserveCeiling)` → false, `terminal()` падал в `failed` и события `ceiling` НЕ писал. Почему это дефект, а не размен: `platform/internal/runs/reconcile.go` читает событие потолка ПЕРВЫМ и дословно говорит «that survives ANY exit: the process may have been killed on its way out, and the fact does not become less true». `PD-113` закрыт ДВУМЯ независимо отказывающими каналами; одна паника забирала оба. Починка узкая: `runWave` присоединяет к панике ТОЛЬКО `*CeilingHalt` — не `context.Canceled` (проверено посадкой: присоединение отмены роняет `TestWaveWorkerPanicSurfacesAsAFailingError`, и правильно, крах не должен читаться как вызванный им же graceful stop); `terminal()` проверяет панику ПЕРЕД потолком, пишет событие `ceiling` и исход `failed`. Код выхода 1 и зеркало «исход = код выхода» не двинуты. Пины: `TestACrashOverACaughtCeilingKeepsBothFacts`, `TestACrashOverACaughtCeilingStillAnnouncesTheCeiling`, `TestACrashJoinedWithACeilingStillExitsAsACrash`. **ПЕРЕ-СКОУП строки 197 — как заказано.** ФЧ-1/4/5 закрыты паком «число согласия» (`D39.187`). **ФЧ-6 сверен кодом и выглядит закрытым**: отказ проекции репортится базисом, отчёт не валится (`internal/pipeline/status.go`, греп `RebillBasisFailed`). **ФЧ-7 закрыт этим паком.** **ФЧ-2, ФЧ-3 и ФЧ-8 НЕ ПРОВЕРЕНЫ НИКЕМ и остаются живым остатком строки** — см. секцию «Что НЕ проверено». --- ## Свобода и её разметка — отчёт ПО КАЖДОЙ строке таблицы промта **«Делай РОВНО так» — исполнено всё, отступлений нет:** порядок 113 → 46 соблюдён (база записана ДО стройки экрана) · СТОП по фикстуре не сработал, все три порога пройдены с запасом · текст заголовка не менялся · статусы строк и подписная таблица не тронуты · нота бита спеку у `FlagCJKArtifact` — флаг СВОЙ · суб-бюджеты ×4.47 как ПОЛ, взято выше с объявленным доводом · жанр снят и из промптов, и из канона брифа · обе посадки дофикса краснеют · ФЧ-7 проверен исполнением (и починен сверх заказа — объявлено) · все запреты «Границ» соблюдены. **«Решаешь сам и аргументируешь» — по каждому пункту решение и довод выше:** развилка производства рода (§1) · второй замок — ВЫНЕСЕН пингом и ратифицирован оркестратором расщеплением, сам не снимал (§1) · данные в 134 — НЕ тронуты, объявлено первой строкой (§3) · числа суб-бюджетов (§4) · форма фикстуры 113 (§2, с названной ценой) · форма тестов и записей каталога · порядок работ (6 → 5 → 3 → 1 → 4 → 2, голден один раз в конце). **Границы:** `manifestVersion`, `StreamVersion`, схема хранилища и версия контракта НЕ двинуты (предъявлено `tmctl manifest`) · новый эмбед-файл не заведён · `FlagCJKArtifact` не переиспользован · семантика переноса слота не тронута · строки 131 · 105(а) · 14 · 119 · 124 · 115 · 160 · 161 · 142 не брались · чужие зоны, `.env` и соседний worktree не трогались. ## Самопроверка исполнением **1. Дифф `^func Test` ПОФАМИЛЬНО.** `grep -rn '^func Test' backend --include=*_test.go | wc -l` → **1105 → 1143**, добавлено 39. **Удалённых имён ОДНО:** `TestEditorSectionFollowsProvenance` — переименование, разбор в шапке. **2. Голден пере-захвачен ОДИН раз, маскированный дифф разобран построчно.** 22 строки провода + 252 версионных. **Диспозиций, флагов и `chunk_status` не двинулось ни одного** (`diff` по этим строкам пуст; 252 строки до и после). ⚠ **Поправка к моей же формулировке, найденная адверсариальным проходом:** сказать «финальные тексты не изменились» было БЫ неверно. `final_text` изменился на всех 8 chunk-строках и `stage_text` на 22 — но ровно на ТОКЕН ХЕША, который фейк-провайдер эхом вкладывает в свой ответ, то есть следствием сдвига запроса, а не сменой вердикта. Точная формулировка: **вердикты не двинулись; каждый финальный текст отличается только эхом хеша запроса.** ⚠ **Вторая поправка того же прохода:** в ГОЛДЕНЕ двинулись `brief_hash`, `classifier_version`, `render_format_version` и `prompt_sha256` ЧЕРНОВОЙ стадии — а `memory_version` и `prompt_version` НЕ двинулись (у фикстуры свой лейбл `v-golden`, а токен фолда неподписанных строк заморожен намеренно). Мой первоначальный перечень осей был шире фактического. `memory_version` двигается на книге с гендерными строками, а не в этой фикстуре. **3. Собственные посадки ВНЕ шести пунктов — 8, механизмом `cmd/tmmutate` на копии дерева.** 6 красных, **2 ПЕРЕЖИЛИ** и НЕ чинены (вне заказа, носитель — строка **252**): `StickyDepth = 2 → 1` не ловит никто · `priorityRank`, отбрасывающий приоритет доверия в бюджете инъекции, не ловит никто. Третья пережившая — `cutTag` без `lang.EmbeddedVersion()` — ПОЧИНЕНА по своей инициативе, потому что на этом компоненте стоит весь довод пункта 3 (`TestTheCutTagActuallyCarriesTheEngineData`, `TestEveryCutInputMovesTheTag`, запись `WB4`; `cutTag` разложен на `cutInputs`/`tag()` — рефактор байт-нейтрален, предъявлено сборками из HEAD и из дерева). ⚠ Методическая заметка, стоившая ложного результата: `tmmutate` на копии дерева НЕ МОЖЕТ судить тесты `cmd/tmctl`, которые собирают бинарь, — копия не git-репозиторий и сборка падает на VCS-штампе, маскируя всё остальное. Гонять копию с `GOFLAGS=-buildvcs=false`. **4. Отдельный проход по СВОЕЙ ГОТОВОЙ работе свежим контекстом — ДВА агента, модель `fable`, оба read-only,** с заданием ФАЛЬСИФИЦИРОВАТЬ шесть заявлений каждый (деньги и провод · вердикты и данные). Ноль не декларирую: они принесли шесть находок, и четыре я починил. **Находки собственного адверсариального прохода — что нашли и что с этим стало:** 1. ⛔ **`bank-apply` СТИРАЛ произведённый род — то есть ровно тот акт, ради которого стоп существует.** `termFromBank` копировал только `Type` и `Aliases`; строка дельты уходила с `gender: ""`, а `loadAutoBank` потом ронял авто-строку как занятый ключ. ПОЧИНЕНО: род переносится вперёд, как переносятся алиасы (это находка движка ОБ СУЩНОСТИ, а решение о РЕНДЕРИНГЕ не просили её выбрасывать); дверь по-прежнему род не ПРИНИМАЕТ. Пин `TestApprovingATermKeepsTheGenderTheEngineProduced`, проверен красным на копии без правки. 2. ⛔ **Мой первый гард пункта 4 закрывал только одно из ДВУХ условий раннего возврата.** Второе — `r.pack == nil`, а нил-пак книга получает без `langpack_root` или с корнем без каталога своей пары. Такая книга несла бы настроенный и забюджетированный контур и не исполнила бы ни строки. ПОЧИНЕНО третьим гардом в раннере (пишущий путь), где гейт и пак есть вместе — конфиг-лоадер этого структурно не видит. 3. ⛔ **`repairReGate` звал `classify` БЕЗ `TargetScripts`** — экран цели на пути ремонта воздерживался, судя везде: починка, вернувшаяся на другом языке, прошла бы ре-гейт, вся работа которого в том, чтобы спросить «это всё ещё пригодный ответ». ПОЧИНЕНО: ре-гейт зовёт тот же классификатор с теми же входами. 4. ⛔ **`classify_budget_usd: 0.50` давал запас 1.45×, а комментарий рядом обещал «≈3×».** ПОЧИНЕНО: 1.00, запас 2.9×, и названо, что по замеру классификатор ДОРОЖЕ рендера. 5. ⛔ **Тест `TestTheLiveEchoGateKeepsItsMeasuredMargin` проходил на фикстуре с ПУСТЫМ off-target классом:** `0/0` = NaN, а любое сравнение с NaN ложно. ПОЧИНЕНО знаменателем-предусловием. Тем же касанием: суррогат целевой стороны привязан к записанному счёту (как уже был исходный), добавлены проверка `target_script_letters ≤ letters` и `TestTheScreenConstantsStillSitWhereTheCorpusPutThem` — константы `langscreen` сверяются с ДАННЫМИ, а не с константами (порог обязан лежать в пустом интервале корпуса, пол улики — не выше самого короткого off-target). 6. ⚠ **`allowshort_wire_test.go` утверждал ОТСУТСТВИЕ маркера — после пункта 3 это утверждение не может упасть.** Заменено на то, что фикстура ещё способна держать: `allow_short` доставляет строку ЦЕЛИКОМ, вместе с её родовой директивой. Плюс поправлены четыре комментария, ставшие ложью: `decisions.go` («род — сид-онли без автопроизводителя»), доккоммент `langscreen` про →en, `BriefHash` про исторический хеш, и три стейл-упоминания маркера в тестах зоны. ## Что НЕ удалось и что НЕ проверено ⚠ Исходов ТРИ, и «не проверено» ≠ «опровергнуто» ≠ «сделано». **НЕ ПРОВЕРЕНО (никем, включая меня):** - **ФЧ-2, ФЧ-3, ФЧ-8 строки 197.** Их я не открывал вовсе. ФЧ-2 — два докстринга `reprice.go` описывают не то, что делает код (детекция перебора односторонняя; «остаток несётся по счёту» неверно). ФЧ-3 — снятый закон approved-only продолжает утверждаться в докстринге теста и в `backend/docs/D15.2-*.md:317`. ФЧ-8 — докстринг `TranslateBook` про «каждый выход через `terminal()`» неверен для паники вне волны · комментарий `dispatchCommands` · шапка рига. Живой остаток строки 197. - **Ничего в этом паке не проверено ПЛАТНЫМ вызовом.** Ни одна модель не вызывалась: санкции на деньги у меня не было и я её не просил. Всё измерено на персистированных чекпоинтах стенда и на фейк-провайдерах. - **Качество рода не измерено.** Что классификатор реально отвечает в третьей колонке на живой книге — не мерено ни разу. Промпт написан консервативно (`none` объявлен самым частым и правильным ответом при нехватке контекстов), но верно ли он определяет пол — вопрос замера, а не стройки. ⚠ Это ПЕРВЫЙ кандидат в следующий полигон-пак: ось рода теперь производит данные, и ложный `male` поедет консистентно через всю книгу — то самое свойство, ради которого консистентность и строилась. - **Экран цели не проверен на живом провале.** Он ловит два образца, которые уже лежат в стенде; поведёт ли он себя так же на СВЕЖЕМ off-target событии — не мерено. Порог 0.50 стоит в пустом интервале и не калиброван (и это по `D39.92` п.1а и не может быть иначе на этом корпусе). - **Цена банкового контура в c1 на реальной книге не мерена.** Числа суб-бюджетов — проекция от десятиглавого замера, не наблюдение. Первый же боевой прогон с контуром даст настоящие числа, и их надо сверить с полом. - **Наличие корпуса контраста на БОЕВОЙ машине.** Я его не видел и видеть не мог. Строка 251. **НЕ СДЕЛАНО СОЗНАТЕЛЬНО (с доводом):** - **Замок №0 не трогал** — базовый банк исключает `Source:"mined"` по денежному контракту `D39.42` п.3. Следствие названо в §1: род не едет на ЧЕРНОВОЙ провод и не поедет, пока цена двух волн не решена отдельно. Не моё решение. - **`ru glossary_header` не тронут** — висячая ссылка на снятый маркер, чинится только правкой `injection.txt`, то есть ценой `cutTag`. Носитель — строка 250. - **Две пережившие мутации не чинены** — вне заказа, носитель 252. - **Строка 204 / `PD-246`: карту причин платформы не правил** — чужая зона. Пинг отправлен напрямую (`textmachine-main-34`), она пере-сняла счёт своей командой и завела у себя; состав контрактного минора несёт оркестратору, потому что изобретать код замечания платформенная сессия не вправе. **НАЙДЕНО И НЕ ЧИНЕНО — ЧУЖИЕ ЗОНЫ (передаю фактом, не правкой):** - ⚠ **Следствие починки ФЧ-7 на стороне платформы, которого я не предвидел.** `pgstore/sink.go` кладёт событие `ceiling` в `paused_reason`, а `runs/reconcile.go:1008` возвращает `paused` с `exit_code = nil`. ⇒ прогон, который УПАЛ поверх потолка, теперь приезжает `paused` и КОД ВЫХОДА теряется — крах становится невидим на строке прогона. Это лучше прежнего для пользователя (ему говорят «добавь денег», и это правда и действие), но хуже для операций. Взвесить и решить — не мне; несу как факт. - ⚠ **Стейл-упоминания снятого маркера вне моей зоны:** `platform/internal/runs/spawn.go:164` (прод-комментарий), `platform/internal/runs/reconcile_test.go:723`, `platform/docs/DEFECT_REGISTER.md:412` (PD-277), `eval/pilot/memory_eval.py:440-452` (заявляет «byte-synced with Go glossaryBlockHeader» и по-прежнему дописывает маркер построчно — зеркало провода в полигоне разъехалось). - ⚠ **`platform/deploy/` ничего не знает о корпусе контраста** (`grep -rn 'contrast_path\|mining:' platform/deploy/` → пусто). Половина строки 251. - ⚠ **Дыра покрытия, найденная платной сессией и переданная мне** (`PD-441`, её ряд): вызов, отменённый В ПОЛЁТЕ по книжному потолку, уходит веткой «No 2xx ever arrived: nothing was billed» → `releaseReservation` и нулевая цена в `request_log`, хотя замер 04.09 показывает отмены на 120756/156469/156470 мс — то есть запрос был выпущен и, скорее всего, оплачен. Латентность разводит два случая (20–31 мс против 156 с). **Я это НЕ чинил: `stagerun.go` в моей зоне, но это ДЕНЕЖНЫЙ путь и отдельный предмет, а не пункт вайр-батча.** Заказ на него — отдельным паком. **ЧЕГО Я НЕ ДЕЛАЛ ПО ГРАНИЦАМ:** не коммитил, индекс и историю не трогал; `platform/` и `eval/` только читал; соседний worktree не открывал; `.env` не читал. ## ДОФИКС ПО ПРИЁМКЕ (04.09) — четыре пункта наряда, все закрыты ⚠ **Класс, который приёмка вскрыла и которого моя самопроверка не нашла: СЕМЬ ЗАЯВЛЕННЫХ ГАРАНТИЙ СУЩЕСТВОВАЛИ ТОЛЬКО КАК КОД.** Двенадцать её посадок пережили полную батарею. Это ровно образец `D39.187` — тот же дефект, что этот пак чинил у чужого пака, повторённый мной. И нашёлся он там, где я сам сказал «ставь гуще», то есть карта слепых зон работает; чего у меня не было — это привычки сажать мутации на СВОЙ новый код, а не только на соседний. **Д1 — пять неприбитых гарантий прибиты, каждая тестом И записью каталога (`WB5`–`WB13`, каталог 96 → 105, все красные одним прогоном).** · **F2, тяжелейшая: живая доставка строки 46 не была прибита вовсе** — `grep -rn 'FlagOffTargetLang' --include=*_test.go` давал ПУСТО. Модуль экрана был прибит офлайн (по руносчёту фикстуры) и по своему пакету, а вердикт, ради которого он построен, на живом пути не проверялся ни разу: переживали и «экран всегда воздерживается» (`Screen(out, nil)`), и «`chunkrun` не передаёт `TargetScripts`», и **снятие флага из `escalatable()` — прямое требование `D39.93` п.2, без которого пойманный чанк молча ТЕРЯЕТСЯ вместо пере-атаки**. Прибито: `TestAnOffTargetCompletionIsFlaggedAndEscalated` (вердикт + деталь + `escalatable` + `!retryable` + эхо остаётся эхом), `TestTheScreenIsInertWithoutTargetData`, `TestTheRunnerHandsTheScreenItsData` (через `classifyOutput` — ЕДИНСТВЕННЫЙ живой call-site, плюс исключение обеих банк-ролей). · **F10: порог экрана не был ИСПОЛЬЗОВАН ни в одном тесте** — случая с долей между границами не было, то есть константа могла быть любой. `TestTheOffTargetThresholdIsUsed`: 0.60 → ok, 0.40 → флаг. · **F1: три гарда контура** — `TestABankContourThatCanNeverFireIsRefused` (лоадер судит КЛЮЧ и не судит ФАЙЛ) и `TestTheContourRefusesAWriteRunItCannotExecute` (обе половины раннего возврата: отсутствующий артефакт и нил-пак; с ПРЕДПОСЫЛКОЙ, что до порчи фикстура открывается, и с обязательной проверкой, что `$0`-чтение той же книги ПО-ПРЕЖНЕМУ работает — `D20.4`). · **F5: гард `TargetScriptNonLatin` в санитайзере** — `TestTheLatinResidueClassIsGatedOnTheTargetsOwnScript`, обе стороны. ⚠ Названная узость: `target-en.txt` в репо нет, поэтому «латинописьменная цель» достижима только через ПУСТОЕ объявление (та же ветка `wordScript == nil`); строку с настоящим `word_script latin` тест получит в день, когда такая цель появится. · **F6: исключение банк-ролей** прибито было только юнитом на `isBankRole`; регресс до «терминолог-only» оставлял батарею зелёной. Теперь ловится через `classifyOutput` (`WB7`). **Д2 — $0-валидация плейсхолдеров ДО первого вызова. ДЕНЬГИ.** Приёмка подтвердила исполнением то, что я принёс и не починил, сочтя вопрос про громкость: отказ на `{{genre}}` приходил ПОСЛЕ купленной черновой волны (`stage=draft cost_usd=0.001820`, `edit wave started`, затем отказ; `drafts=1 edits=0`). **Вопрос был про МОМЕНТ, и я его не расслышал.** Построено: `CheckPlaceholders` сканирует шаблон по тому же ЗАКРЫТОМУ набору, что подставляет `Render` — набор вынесен в одно определение (`renderVals`), потому что два списка это и есть способ, которым валидатор благословляет имя, которое рендер отвергнет. Вызов стоит в `LoadPromptTemplate` — единственной воронке, через которую проходят ВСЕ шаблоны: стадии, классы репэйра и обе банк-роли. Живой источник таких пакетов настоящий: `grep -rl '{{genre}}' eval/ | wc -l` → **27**. ⚠ **Заказанная смена поведения, объявляю (D39.183):** `TestRenderRejectsUnknownPlaceholder` описывал отказ ОТ `Render`; отказ переехал на загрузку. Тест не ослаблен — он теперь держит ОБА рубежа (гейт на загрузке И собственный отказ `Render`), плюс что закрытый набор проходит целиком, плюс что отказ НАЗЫВАЕТ и маркер, и то, что движок принимает. **Д3 — закон-блок даёт ОДИН приказ на исходный термин. Ратификация исполнена ровно так.** Дедуп переведён с `(src,dst)` на `src`. Довод, который я принимаю целиком и не смягчаю: пока у блока было два заголовка, две передачи одного термина были двумя РАЗНЫМИ высказываниями — «это канон» и «это неподтверждённый рабочий вариант»; **мой же пункт 3 схлопнул их в два ПРИКАЗА об одном термине**, а с разными родовыми директивами — в два противоречивых приказа об одном персонаже. Побеждает первая строка, и «первая» тут не случайность: `Select` отдаёт в приоритетном порядке, `priorityRank` ставит `Confirmed` раньше `Ambiguous` — то есть подписанная. Конфликт не спрятан, а РАЗВЕДЁН: движок уже пишет о нём WARN оператору (`seeding.go`), и это правильное деление — **модель получает один закон, оператор получает разногласие**. Отбрасывание строки на загрузке не бралось: это онтология банка, а нужна была узкая правка провода. Пин `TestTheLawBlockGivesOneOrderPerSourceTerm` кормит неподписанную строку ПЕРВОЙ (дедуп, хранящий первую строку ВХОДА вместо первой строки приоритета, прошёл бы фикстуру в естественном порядке) и отдельно держит, что ГОМОНИМИЧНЫЙ dst — два разных исходных термина — остаётся двумя строками. **Д4 — числа отчёта поправлены.** F7: «ноль ложных на 1132» заменено на воспроизводимое над репозиторием — **ноль ложных на 44 ТРУДНЫХ здоровых**, с явным разделением «обход дал 1162/1132» и «в git уехала выборка 74 строк», и с описанием, как выборка отобрана. Это ровно класс «число одной величины под именем другой», который я чинил в пункте 4 и повторил в своём же отчёте. F8: расхождение шапки и секции самопроверки (1133/29 против 1135/31) снято — обе теперь **1143**, добавлено 39. ⚠ **F11 — РИСК ДИЗАЙНА, не чинен, называю (вход в калибровку).** На латино-тяжёлом ЗДОРОВОМ русском экран цели даёт ложные `off_target`: русский с пиньинь-глоссами → 0.461, инструкции с shell-командами → 0.077. Ложный флаг ЭСКАЛИРУЕТСЯ, то есть стоит платного вызова. Корпус, на котором порог поставлен, — ОДНА сянься-новелла; жанр с системными окнами, кодом или плотной латинской терминологией не мерен вовсе. **Перед первым платным прогоном книги другого жанра порог обязан быть пере-калиброван на её корпусе.** Это не опровержение экрана (на измеренном жанре ноль ложных на трудных), это граница его калибровки. **Батарея после дофикса:** `MAKE_EXIT=0`, `0 issues`, 19 пакетов `ok`, скипы те же три. **Голден пере-захвачен — 0 изменений** (дофикс не двинул ни одного байта провода в фикстуре). Тесты **1105 → 1143**, удалённых имён по-прежнему одно и то же переименование. Каталог **92 → 105**, записи `WB1`–`WB13` красные. ## КРУГ 2 ПЕТЛИ (`D39.191`) — НЕ ЗАМКНУЛСЯ: веер нашёл 21 пережившую посадку, все закрыты. Круг 3 обязателен ⚠ **Условие замыкания жёсткое, и оно не выполнено:** круг замыкается, только когда проход с НЕПУСТЫМ веером не нашёл ни одной пережившей посадки. Этот нашёл двадцать одну. Ниже — веер, все находки с диспозициями, что я перепроверила сама, и чего круг не покрыл. ### Веер **Три источника, разные ракурсы.** (1) Агент `fable`, read-only — ДОФИКС, которого свежий контекст не видел: `CheckPlaceholders`, дедуп по `src`, новые тесты гардов и экрана на ВАКУУМНОСТЬ. (2) Агент `fable`, read-only — НЕПОКРЫТОЕ, ровно по моему же списку слепых зон: `volume.go` (пункт 6, чужой дофикс), закон-блок на книге с НЕПОДПИСАННЫМИ строками, бласт-радиус `InjectionTrust`, свип леджера, мелкие поверхности. (3) **МОИ собственные посадки — В ДАННЫЕ**, чего в круге 1 не было вовсе: фикстура корпуса, `prompt-labels.json`, `pipeline-c1.yaml`, промпт классификатора, `injection.txt`. **Посадок всего: 12 моих + ~26 агента A + ~60 агента B.** Мои: 11 красных, 1 пережила. ### Что нашлось — двадцать одна пережившая, по классам **А. ЖИВОЙ ДЕФЕКТ, внесённый моим же дофиксом (1).** · **Дедуп закон-блока по голому `src` ронял ВТОРУЮ ПОДПИСАННУЮ строку.** Ключ уникальности банка — `(src, sense, since, until)`, то есть одна поверхность законно несёт несколько подписанных канонов: 青山-фамилия и 青山-направление. Мой дедуп выбрасывал один из них МОЛЧА, при том что трансляторный блок продолжал рендерить оба — два провода разъезжались. Правило исправлено на то, чем оно должно было быть с самого начала: **уступает НЕПОДПИСАННАЯ строка, и только подписанной; подпись не роняется никогда.** Пин красный на возврате к старому ключу. **Б. ДЕНЬГИ (2).** · **`ReachableModels` не знал банк-ролей.** `buildClients` пре-строит именно этот список, `CheckKeys` требует именно эти ключи — оба на ОТКРЫТИИ. Модель терминолога или классификатора, не заведённая в `models.yaml` или без ключа в окружении, проходила ВЕСЬ преflight и убивала прогон на стопе майнинга — после купленной черновой волны. Латентно, пока контур не жил в боевом конфиге; пункт 4 делает это живым. · **Банкнотный канал покупает вывод, который на этой конфигурации никто не прочитает** — единственный читатель за ранним возвратом. Не отказ (прогон корректен, срез делает свою работу), а предупреждение с ценой. **В. УТВЕРЖДЕНИЯ О СТРУКТУРЕ, ВЫДАННЫЕ ЗА ГАРАНТИИ (4) — класс, которого я в круге 1 не назвала.** · «валидатор и рендер читают одну таблицу» — прибито только ПРИМЕРАМИ; валидатор-надмножество проходил всё; · «проверка стоит в единственной воронке и покрывает все пути» — **все четыре пути загрузки промптов обводятся вокруг гейта, батарея зелёная.** Моя же формулировка из отчёта по Д2; · «порог лежит в пустом интервале» — порог 0.50 → 0.45 переживает всё И НЕ ДВИГАЕТ ВЕРСИЮ: резюмнутый чанк пере-судился бы по порогу, за который никто не платил. ⇒ `langscreen.Version` теперь ВЫВОДИТСЯ из констант, `classifierVersion` стал var, правка порога роняет голден по построению; · «свип леджера покрывает обе банк-роли» — свип ходил по НАЙДЕННОМУ и никогда по ЗАПИСАННОМУ, поэтому удаление роли из свипа оставляло её запись сиротой, а промпт — неприбитым. ⇒ проверка сирот. **Г. ДАННЫЕ (1) — и это то, ради чего норма про посадки в данные написана.** · **Фикстура корпуса, размягчённая до красивого числа, проходила всё.** Тест утверждает пол «не меньше 3×», а пол не измерение: обнуление исходных рун у ЕДИНСТВЕННОГО худшего здорового образца оставляло батарею зелёной и рапортовало запас ЛУЧШЕ, чем корпус когда-либо давал. ⇒ леджер записанных чисел (30/44 строк · 0.011655 · 0.976706 · 346 букв), по образцу леджера лейблов: пере-взять корпус законно, но это стоит правки здесь и фразы в отчёте, а не ничего. **Д. РАСЩЕПЛЕНИЕ `Disp`, прибитое только там, где две половины СОВПАДАЮТ (3).** · липкий перенос, ПЕРЕ-ВЫЧИСЛЯЮЩИЙ матч-доверие, переживал всё: единственный пин использует строку, чей `src` И ЕСТЬ сработавший ключ, поэтому пере-вычисление совпадает с наследованием. Разводит их строка с ханьским `src` и коротким фонетическим АЛИАСОМ — там перенос re-trusted, и род едет к сущности, которой на странице может не быть; · липкий перенос, ВЫВОДЯЩИЙ доверие из диспозиции, тоже переживал: неподписанная строка на чистом ключе теряет род в момент переноса — дверь строки 210 в липкой форме; · диспозиционная ось `priorityRank` не отличима от статусной ни одной фикстурой. Это одна из ДВУХ, переживших круг 1, и теперь на ней стоит мой дедуп. ⇒ прибита состоянием, которое оси разводит: две ПОДПИСАННЫЕ строки, одна на collision-prone ключе, под связывающим бюджетом. **Е. ЧУЖОЙ ПАК (пункт 6), которого свежими глазами не видел никто (6).** Из двадцати посадок в `volume.go` шесть пережили, и все шесть — в ОПЕРАТОРСКОМ ПРЕДЛОЖЕНИИ и в двух неотфикстуренных ветках `reconcile`: счёт «%d paying output unit(s)» без флагнутых (недо-счёт того, за что заплачено) · клауза про $0-попутчиков · развилка головы, спрошенная про `LeftFresh` вместо `Left()` · свободный юнит, флагнувшийся на резюме, посчитанный оплаченным · пере-деланный юнит, флагнувшийся и оставшийся В ОБОИХ счётчиках · и **порядок `bound()` ДО `reconcile`, от которого корректность отчёта зависит СЛУЧАЙНО**. Прибиты пятью тестами; последний — документирован в `waverun.go` с прямым указанием, какой «естественный рефактор» его сломает. **Ж. Прочее (4):** липкие записи, исчезающие из закон-блока · глубина липкого окна · сироты леджера · `injection.txt` без родовой строки (последнее — уже красное, поймано `TestDC3GenderInjection`). ### Что я перепроверила сама, а что взяла со слов **Перепроверила посадкой ДО починки (все, кроме одной):** дедуп по `src` · порог экрана · валидатор-надмножество · обход воронки на пути классификатора · диспозиционная ось · липкий перенос (обе формы) · сирота леджера (обе формы) · липкая запись в закон-блоке · банкнотный канал · размягчённая фикстура. **Взяла со слов:** `H2` (два ряда с одним id — недостижимо через стор), `H7` (битый артефакт контраста молча даёт пустой контраст), и стейл-текст `glossary_header` — про него я уже знала. ⚠ **И одна собственная ошибка, которую поймал каталог, а не я:** первая редакция теста про `ReachableModels` читала `pipeline-c1.yaml`, где модель банк-роли СОВПАДАЕТ с моделью черновика, — то есть тест не мог упасть. Посадка сказала `SURVIVED`, я переписала тест на конфиг, где банк-модель своя. **Механизм проаудировал мой пин; чтение бы не проаудировало.** ### Чего круг НЕ покрыл - **Пункт 5 (жанр) и цепь рода end-to-end** — ни один агент их не атаковал: я дала им дофикс и непокрытое, считая эти два закрытыми кругом 1. Остаются проверенными одним проходом. - **`$0`-проекции на дефектной книге** — `status`/`report`/`export`, реально отрендеренные: и мой тест, и посадки доказывают только, что КОНСТРУКТОР открывается. - **Липкий перенос до РЕДАКТОРСКОГО провода сквозным прогоном** — ни одна фикстура не гонит прономинальный чанк с переносом в edit-юнит; всё прибито на уровне `membank`. - **Настоящая латинописьменная цель** — `target-en.txt` в репо нет; ветка достигается пустым объявлением, и тест это говорит. - **`eval/`-харнессы** — вне модуля бэкенда, не гонялись. - **Сверка двух агентов между собой** — снова не делалась. ### Числа круга Батарея `MAKE_EXIT=0`, `0 issues`, 19 пакетов, скипы те же три. **Голден БАЙТ-ИДЕНТИЧЕН** тому, что был до починок круга (единственное движение голдена за круг — `classifier_version` от вывода версии экрана из констант; вердикты не двинулись). Тесты **1105 → 1156**. Каталог **92 → 120**, записи `WB1`–`WB29` красные одним прогоном. Удалённых имён по-прежнему одно — переименование `TestEditorSectionFollowsProvenance`. ## КРУГ 3 ПЕТЛИ (`D39.191`) — ЗАМКНУЛСЯ ПО СОДЕРЖАНИЮ, НО НЕ ПО УСЛОВИЮ: веер нашёл 20 переживших посадок и 1 дыру исполнением, все закрыты ⚠ **Условие замыкания не выполнено и здесь.** Круг замыкается, только когда проход с непустым веером не нашёл НИ ОДНОЙ пережившей посадки. Этот нашёл двадцать — плюс дыру, найденную не посадкой, а исполнением. Ниже веер, все находки с диспозициями, что я перепроверила сама, и чего круг не покрыл. ### Веер **Два источника, и это первый круг, где второй — не мой агент.** (1) Агент `fable`, read-only, работавший в СВОИХ копиях дерева (рабочее дерево не тронуто — подтверждено им и сверено по `git status`): **68 посадок в семи предметах**, 48 красных, 20 переживших, 0 несостоявшихся. (2) **Круг оркестратора** — независимый веер по тому же батчу, девять находок, пять новых для меня. По трём пунктам два веера сошлись НЕЗАВИСИМО (дедуп полисемии · порог без пина · класс структурных утверждений), и это первое за три круга свидетельство, что находки воспроизводимы между читателями, а не являются вкусом одного. ### ⛔ ГЛАВНОЕ: денежная дыра, которую круг 2 ОБЪЯВИЛ ЗАКРЫТОЙ, была открыта Мой фикс круга 2 внёс банк-роли в `ReachableModels()` и на этом остановился. **`CheckKeys` читает этот список ТОЛЬКО в лейбл-ветке.** Безлейбловая книга — shipping-дефолт — идёт второй веткой, которая собирала модели стадий руками и про ворота не знала. Проверено исполнением: терминолог, классификатор и ремонт на провайдере с пустым `api_key_env` проходили префлайт целиком, `CheckKeys` возвращал nil. Прогон покупал черновую волну и умирал на воротах. **Почему тест круга 2 был зелёным поверх дыры:** он утверждал СПИСОК, а не префлайт. Пин на списке не есть пин на проверке, которая его читает. **И вторая половина той же дыры:** рантайм-список `reachableModels()` тоже не был прибит — посадка «только стадии» (без ремонта и банк-ролей) держала ВЕСЬ пакет `pipeline` зелёным. Причина — совпадение `pipeline-c1`, воспроизведённое в фикстурах: каждая фикстура ставит воротам `model: fake-model`, ту же модель, что у стадий. **Закрыто:** одно определение `gateModels()`, которое читают обе ветки `CheckKeys` и `ReachableModels`; тест зовёт `CheckKeys`, а не смотрит список; и фикстура, где банк-роль ходит СОБСТВЕННОЙ моделью, с пином на пре-строенной карте клиентов. ### Что нашлось ещё — по классам **А. ЦЕЛЬ С CJK-ПИСЬМОМ НЕ ЭКРАНИРОВАЛАСЬ ВООБЩЕ** (находка оркестратора). Гейт `!isCJKTarget` принадлежал ЭХО-правилу, а держал оба правила сразу. «Вывод в письме ИСТОЧНИКА» для →ja бессмысленно — верный перевод zh-книги полон ханьцзы; «вывод в письме ЦЕЛИ» отвечается прекрасно. Итог: →ja/→zh/→ko не судились ничем, при том что доккоммент `langscreen` обещал обратное. **Это бьёт в цель проекта №2:** на ревью-вопрос «заработает ли пара, которой в репо нет, без правки Go» ответ для CJK-целей был «нет». Экран вынесен из-под гейта, эхо-правило осталось под ним. Документированный предел супермножества (китайский вывод для →ja не флагуется) прибит **как ПРОМАХ**, чтобы никто не принял экран за защиту от zh-эха на →ja. ⚠ **`classifierVersion` НЕ двигали — ратифицировано оркестратором.** Для →ru поток управления побайтово тот же (`!isCJKTarget` истинно и до, и после, обе ветки в том же порядке), →CJK-снапшотов не существует, а строка в этом батче уже сдвинулась дважды и пере-снапшот уже предписан единым актом. Различитель на будущее: **бамп должен любой смене, способной пере-вердиктить СУЩЕСТВУЮЩИЙ снапшот** — не «кажется, безопасно». **Б. ПРОИЗВОДНОСТЬ ВЕРСИИ ЭКРАНА БЫЛА ЗАЯВЛЕНА И НЕ ДЕРЖАЛАСЬ (3 посадки).** Доккоммент `Version` говорит «выведена по построению, поэтому сдвиг порога забирает громкий `--resnapshot` с собой». Не проверял никто. Посадка: переписать `var` литералом, который он сейчас печатает, и сдвинуть порог 0.50 → 0.45 — строка не двинулась, голден не двинулся, оба интервальных пина прошли (0.45 внутри пустой полосы), весь пакет зелёный. Резюмированный чанк пере-вердиктился бы порогом, за который никто не платил. Третья дверь: `%.2f` не выражает 0.504 — окно точности ±0.005. **Закрыто:** тест пересчитывает строку из констант, и round-trip-guard требует, чтобы напечатанный порог читался обратно тем же числом. Формат НЕ расширен намеренно — это стоило бы `--resnapshot` всем книгам за правило, которое не менялось; расширение теперь осознанный акт. **В. ГРАНИЦА СРАВНЕНИЯ, КОТОРУЮ НЕ ВЫРАЖАЕТ НИ ОДНА КОНСТАНТА.** `share < floor` → `<=` пережило весь пакет: ни одна фикстура не сидела ровно на линии. Прибито фикстурой ровно на 200 буквах, из которых ровно 100 целевых — доля 0.50 без плавающего люфта. **Г. ВАЛИДАТОР ПЛЕЙСХОЛДЕРОВ — ТРИ ДВЕРИ.** (1) Сканирование только System-части пережило всё — каждая фикстура кладёт плохой маркер в системную половину, а самое вероятное место для автора — пользовательский хвост, где живут почанковые переменные. (2) Снятие проверки незакрытого `{{` пережило. (3) Тест «равенства множеств» обходит `placeholderNames()`, то есть таблицу РЕНДЕРЕРА, и доказывает только «рендерер ⊆ валидатор»; дорогое направление — обратное, и оно было прибито четырьмя ЛИТЕРАЛЬНЫМИ словами, так что пятое слово проходило насквозь. **Закрыто устранением, а не пином: валидатор ТЕПЕРЬ ЕСТЬ РЕНДЕРЕР** — `CheckPlaceholders` рендерит по настоящей таблице значений. Второго списка не существует, расходиться нечему. **Д. ЗАКОН-БЛОК: ПОДПИСЬ ПРОТИВ УВЕРЕННОСТИ (5 посадок).** Подпись — это СТАТУС, а не уверенность матча: подписанная строка, сработавшая по сомнительному ключу, всё равно канон, которому уступают. Ключевание набора подписей на диспозиции пережило. Уступать должен ЛЮБОЙ неподписанный статус, а не только `draft` — `auto` пишет майнер, то есть ровно та строка, ради подчинения которой правило и существует. Плюс: подписанная строка с ПУСТЫМ переводом не канон (иначе термин исчезает из блока), несимметричный `TrimSpace` разрушает набор, и однопроходная версия зависит от порядка. **Отдельно — вакуумность в моём собственном тесте:** его комментарий утверждал, что случай (1) держит независимость от порядка, а стоящий там же `sortByPriority` это утверждение обнулял. Комментарий исправлен, независимость от порядка вынесена в отдельный случай, который рендерит блок НАПРЯМУЮ, в обоих порядках. **Е. ЛИПКИЙ ПЕРЕНОС: ПОЛОВИНА ДИСПОЗИЦИИ.** Перенос наследует обе половины, но пересчёт диспозиции ИЗ СОБСТВЕННОЙ ПОВЕРХНОСТИ строки пережил: в прибитой фикстуре `src` сам и есть сомнительный ключ, поэтому пересчёт воспроизводит тот же ответ. Разделяющая фикстура (ханьский `src`, сомнительный кана-алиас) существовала, но утверждала только `KeyTrusted`. Под посадкой перенос молча повышался до `Confirmed` — пропуск принудительного пост-чека и место повыше в бюджете, — а провод молчал, потому что половина доверия цела. Это D16.2-повышение в чужом пальто. **Ж. ЛЕДЖЕР КОРПУСА ПИНИЛ ЭКСТРЕМУМ, А НЕ ПОПУЛЯЦИЮ (5 посадок).** Второй по трудности здоровый образец можно было смягчить, второй по низости целевой — тоже, а трудную строку — заменить числами лёгкой ПОД ЕЁ ЖЕ id: счётчики, экстремумы и множество id держались. И у интервала не было записи про ВТОРУЮ сторону: доля off-target могла уехать 0.000 → 0.490 при всех зелёных тестах, и порог 0.50 сел бы прямо на образец, пока леджер говорит «полоса пуста». **Закрыто:** запись `wantBestOffTargetTgt` и **дайджест по всей популяции** (id · метка · четыре счётчика, сортировка по id) — пере-взятие корпуса стало осознанным актом, переписывающим строку в том же коммите. **З. ОПЕРАТОРСКОЕ ПРЕДЛОЖЕНИЕ: ЧИСЛО ФЛАГОВ ПЕЧАТАЛОСЬ ЧИСЛОМ ПЕРЕДЕЛОК.** Пережило весь пакет: обе фикстуры, читающие это предложение, имели `Reworked == Flagged == 1`. Разведены. **И. ФЛАГ, РАДИ КОТОРОГО ПОСТРОЕН ПУНКТ 2, БЫЛ САМЫМ БЕЗОБИДНЫМ В ПАСПОРТЕ** (находка оркестратора). `flagReasonSeverity` не знал `off_target_lang` → дефолт 8, ниже `length` (6). Глава, вернувшаяся не на том языке, показывала «length» как худшую проблему. У функции не было ни одного теста. **Закрыто:** switch стал картой, а исчерпаемость держит тест, читающий константы `FlagReason` **из исходника через go/ast** — список в тесте гнил бы ровно так же, как список в коде, и заверял бы гниль. **К. ВТОРОЙ CALL-SITE `classify`** (находка оркестратора). `repairReGate` собирал `classifyInput` руками из тех же полей, что `classifyOutput`. Поле `TargetScripts` однажды уже забыли там, починили руками — и посадка показала, что починку не держит ничто. **Закрыто устранением:** один конструктор `classifyInputFor`, пин на нём через рефлексию — любое поле, пришедшее нулевым, валит тест. Список полей в тесте не пишется: его обновлял бы тот же, кто забыл обновить конструктор. **Л. ДВЕРЬ 3 ГЕНДЕРНОГО ТЕСТА ОБЕЩАЛА НЕ ТО, ЧТО ДЕРЖИТ** (находка оркестратора, подтверждена исполнением). Её комментарий говорил: «впустят mined-строки в базовый банк — покраснею». Не краснеет: внутри ОДНОГО прогона черновая волна покупается ДО ответа классификатора, поэтому никакое правило про банк не положит род на тот провод. Утверждение об отсутствии оставлено как утверждение о ПОРЯДКЕ, а денежный контракт теперь утверждается там, где живёт — на двух материализованных банках: обогащённый несёт mined-строку, базовый её не выбирает. **М. ИНСТРУМЕНТ ТЕРЯЛ СВОЙСТВО «ГОНЯЕТСЯ ЦЕЛИКОМ»** (находка оркестратора). Протухший якорь `AF-keys-file-reason-covers-all` (протух ещё до этого пака, на `8adcb86`) возвращал ОШИБКУ ПРОГОНА и клал весь каталог на 33-й записи из 120 — а прогоны через `-id` продолжали проходить, и никто не видел. **Закрыто:** протухание стало ПЕРЗАПИСНЫМ вердиктом `ROTTED` — прогон идёт дальше, выход остаётся ненулевым, запись предъявляется. Якорь починен. ### Что я перепроверила САМА, не приняв на слово - **Три находки оркестратора, где код на вид противоречил заголовку** (`repair.go` передаёт `TargetScripts`; `CheckPlaceholders` сканирует весь `canon` и ловит незакрытый `{{`; `TestUnionStickyNewestWins` на вид ловит keep-first) — прогнала собственные посадки. Две подтвердились как непокрытость, одна — нет. - **`UnionSticky` (его находка №4) — ОТВЕДЕНА.** Четыре независимые посадки красные. Оркестратор проверил свою на чистой копии `b8154cd` и снял её сам с точным разбором: его «инверсия» (обход новое→старое с keep-first) ПОВЕДЕНЧЕСКИ ЭКВИВАЛЕНТНА оригиналу (обход старое→новое с перезаписью). **Третий класс ложной зелени за сутки — посадка, не меняющая поведения**, рядом с моими двумя: упавшая сборка, прочитанная как зелень, и обрезанный вывод, прочитанный как ноль. Общее у всех трёх: **читатель верит ВЕРДИКТУ, не проверив, что его произвело.** - **Дыра `CheckKeys`** — не поверила отчёту агента: написала тест, увидела его красным на всех трёх воротах, потом чинила. - **Каждая из 19 новых записей каталога предъявлена красной прогоном.** Одна (`WB41`) вернулась SURVIVED — **моя фикстура случайно давала верный ответ и под посадкой** (неподписанная строка была `Confirmed` и сама наполняла набор подписей). Фикстура переписана так, что подпись — единственный возможный источник; предъявлена красной. ### ⚠ Чего круг НЕ покрыл - **Причина `S6e`** — совпадение ли это фикстур или у банк-ролей есть второй путь к клиенту помимо `clientFor`. Названо агентом, не открыто; я закрыла СЛЕДСТВИЕ (пин на карте клиентов), не причину. - **Сквозной прогон дыры `CheckKeys`** через `NewRunner` → волна: закрыто на уровне `CheckKeys` и пре-строенной карты, но что происходит на живом проводе с ключом-пустышкой, никто не гонял. - **Резюме через смену версии** — end-to-end пере-вердикта резюмированного чанка нет ни одного теста; вся аргументация про `--resnapshot` держится на чтении. - **Конвенционный путь стадийного промпта** — пер-путевой тест гоняет только `prompt_override`. Маркер внутри вырезаемого комментария проходит по построению, и НАМЕРЕННОСТЬ этого никем не проверена. - **Два НЕПОДПИСАННЫХ ряда одной поверхности** оба рендерятся: «один приказ на термин» держится только когда подпись есть. Наблюдение агента, теста нет ни в ту, ни в другую сторону. - **`precomputeSticky`** — сброс на границе главы и запись переноса, заблокированного спойлером. - **Сам харнесс `tmmutate`** (отпечаток и восстановление) и единственная запись `expect: survives` (`G-byte-gate`) не ревьюились ни одним кругом из трёх. - **Ракурсы, унаследованные непокрытыми из круга 2 и не открытые снова:** `$0`-проекции на дефектной книге · липкий перенос до редакторского провода сквозным · настоящая латинописьменная цель (`target-en.txt` в репо нет) · `eval/`-харнессы вне модуля. - **F11 остаётся риском дизайна, не чинен:** порог экрана калиброван на ОДНОЙ сянься-новелле; на латино-тяжёлом здоровом русском даёт ложный `off_target` (0.461 с пиньинь-глоссами, 0.077 с shell-командами), а ложный флаг ЭСКАЛИРУЕТ — то есть стоит платного вызова. Оркестратор забрал носителем. - **Круг 3 не ревьюил мои правки круга 3.** Копии агента сняты до них. Четвёртый круг, если он будет, начинается отсюда. ### Числа круга Батарея `MAKE_EXIT=0`, `0 issues`, все пакеты `ok` (`pipeline` 571 s под `-race`), скипы те же. **Голден в этом круге не трогали, и `TestGoldenDeterminism` проходит против него** — круг не сдвинул ни одного байта провода. Тесты **1156 → 1173**. Каталог **120 → 141**; **все двадцать одна новая запись предъявлена КРАСНОЙ** (`WB41` — со второй попытки, после починки фикстуры, которая случайно давала верный ответ и под посадкой). ⚠ **КАТАЛОГ ПРОГНАН ЦЕЛИКОМ — впервые, и первый же целый прогон окупил починку инструмента.** 141 запись: **136 RED · 0 SURVIVED · 0 NOTHING · 1 записанный `survives` (`G-byte-gate`, аргументирован) · 4 ROTTED**. Протухли четыре МОИ ЖЕ записи, чьи якоря увезли рефакторы кругов 2–3: `WB5` (сборка `classifyInput` уехала в конструктор), `WB12` (правило дедупа исправлено кругом 2 — запись описывала регрессию, которую я же и починила), `WB16` (у валидатора не стало собственного списка), `WB21` (банк-роли уехали в `gateModels`). **Под прежним поведением прогон лёг бы на первой из них, и трёх остальных никто бы не увидел** — ровно то, что произошло с `AF-keys-file-reason-covers-all` и держалось незамеченным два пака. Все четыре пере-навешены на нынешние выражения тех же свойств (у `WB12` и `WB16` заодно переписан `why`: свойство изменилось, а не только адрес) и предъявлены красными. `AF` в целом прогоне — **RED**, то есть починка якоря проверена не на слово. ## Файлы **Изменены:** `internal/pipeline/{disposition,chunkrun,waverun,events,manifest,mining,terminologist,repair,render,runner}.go` · `internal/membank/{memory,mempostcheck,decisions}.go` · `internal/terminology/{terminology,classify}.go` · `internal/miner/miner_emit.go` · `internal/checks/sanitizer.go` · `internal/config/{book,pipeline}.go` · `internal/lang/embedded.go` · `internal/store/migrate.go` · `cmd/tmctl/render.go` · `cmd/tmmutate/mutations.json` (92 → 96) · `configs/pipeline-{c1,c2,arm-*}.yaml` · `prompts/zh-ru/*.md` (шесть — жанр; `classifier.md` — третье поле) · `example/book.yaml` · тесты и голден. **Новые:** `internal/langscreen/{langscreen,langscreen_test}.go` · `internal/pipeline/{cuttag_test,gender_wire_test,offtarget_corpus_test,volumepanic_test,offtargetflag_test,contourpreflight_test}.go` · `internal/pipeline/testdata/offtarget-corpus.json` · `internal/config/{bank_contour_test,genre_retired_test}.go` · `internal/checks/latinguard_test.go`. ## Команды приёмки ``` cd backend && make battery # MAKE_EXIT=0, 0 issues, 19 пакетов ok, 3 скипа go test ./internal/pipeline/ -run 'Gender' -v # производитель рода, три двери доставки go test ./internal/pipeline/ -run 'OffTargetCorpus|LiveEchoGate|LatinOffTarget|TargetScreen|TwoScreens|ScreenConstants' -v go test ./internal/langscreen/ -v # изолированный модуль экрана go test ./internal/config/ -run 'BankContour|BankRoleBudgets|Genre' -v go test ./internal/membank/ -run 'ApprovingATermKeeps|LawBlockGivesOneOrder' -v # род переживает подпись; один приказ на термин go test ./internal/pipeline/ -run 'OffTargetCompletionIsFlagged|RunnerHandsTheScreen|ThresholdIsUsed|ContourRefusesAWriteRun|RenderRejectsUnknownPlaceholder' -v go test ./internal/checks/ -run 'LatinResidueClassIsGated' -v # вторая половина дыры 46, обе стороны go test ./internal/pipeline/ -run 'ACrashOverACaughtCeiling|StopLineSaysTheGrant|OneCarriedUnit' -v cp -a backend /tmp/mut/backend && cd /tmp/mut/backend && GOFLAGS=-buildvcs=false \ go run ./cmd/tmmutate -root . -id WB1-head-always-end-of-book,WB2-head-keyed-on-the-carry,WB3-bound-border-drops-a-single-carry,WB4-cut-tag-drops-the-embedded-data,WB5-target-screen-never-sees-the-target,WB6-off-target-flag-not-escalatable,WB7-bank-role-exemption-narrows-to-one-role,WB8-latin-residue-runs-on-a-latin-target,WB9-contour-configured-and-inert,WB10-missing-contrast-costs-a-wave,WB11-nil-pack-contour-never-runs,WB12-two-orders-for-one-term,WB13-placeholder-refusal-arrives-after-a-paid-wave grep -rl '{{genre}}' backend/prompts/ | wc -l # 0 grep -rn '^func Test' backend --include=*_test.go | wc -l # 1143 python3 -c "import json;print(len(json.load(open('backend/cmd/tmmutate/mutations.json'))))" # 105 ``` ### 04.09 — записка-план вайр-батча «род · экран цели · заголовки инъекций» (промт `BACKEND_WIREBATCH_SESSION_PROMPT.md`, сессия `textmachine-main-7e`) > **Скоуп — шесть пунктов промта.** (1) 210: род производится авто-путём, доказательство сквозным прогоном «произведено → отрендерилось». (2) 113 → 46 в этом порядке: корпус-фикстура и регресс на реальный запас боевого гейта, потом экран цели именованным флагом + вторая половина дыры `detectLatinInsertion`. (3) 134: единый закон-блок редактора, маркер ⟨проверить⟩ с провода, то же у транслятора. (4) 140: банковый контур в `pipeline-c1.yaml`, суб-бюджеты ×4.47. (5) 184(а): `{{genre}}` из шести промптов пары и поле из канона брифа. (6) ДОФИКС чужого пака D39.187 п.4 (две посадки + граница `bound()` + три числа) и ФЧ-7 строки 197 — ПРОВЕРКОЙ, не стройкой. > **Инварианты.** Не коммичу — дерево на лендинг оркестратору. НЕ двигаю: схему хранилища · `manifestVersion` · `StreamVersion` · версию контракта. Новый эмбед-файл не завожу. `FlagCJKArtifact` не переиспользую (снято D39.93 п.2). Статусы строк и подписная таблица в 134 не трогаются (D39.104 п.1). Семантику переноса слота не трогаю. Текст заголовка редактора не меняю — он байт-идентичен арму `AM-noclause` пробы 18 (`experiments/18-editor-wire-probe.md` §0.3). > **Развилки, объявленные ДО кода.** (1) род — производится КЛАССИФИКАТОРОМ (третье поле его ответа), а не терминологом и не третьим проходом: ноль новых вызовов, парсер классификатора позиционный и закрыто-словарный. (2) Второй замок (`Confirmed`-фильтр рендера рода) — вынесен пингом оркестратору на ратификацию, сам не снимаю. (3) 134 — снимаю РЕНДЕР в Go, `internal/lang/data/injection.txt` НЕ трогаю: правка данных двигает `EmbeddedVersion` → `cutTag` → `manifest_key` → снос `unit_resolutions` книги ПАРАЛЛЕЛЬНОГО платного прогона платформы. > **Что НЕ делаю.** Чужие зоны `platform/` `frontend/` `eval/` и соседний worktree. Строки 131 · 105(а) · 14 · 119 · 124 · 115 · 160 · 161 · 142. > **Самопроверка исполнением.** Дифф `^func Test` пофамильно до/после (удалённых имён 0) · маскированный дифф голдена (только названные версионные оси + ровно две строки диспозиций) · собственные посадки `tmmutate` ВНЕ шести пунктов на копии дерева · отдельный адверсариальный проход свежим контекстом (модель назову) · отчёт о движении `cutTag`: `tmctl manifest` до и после. ### 02.09 — эхо-записка пака «число согласия на пути второй покупки» (промт `BACKEND_CONSENT_SESSION_PROMPT.md`, сессия `textmachine-77`) > **Канала к оркестратору нет:** адрес в `/tmp/textmachine-channel` (`textmachine-33`) в `ListAgents` отсутствует, промт писан на другой машине — вопросы едут секцией отчёта ниже. Дерево на входе чисто, HEAD `494c4ef`; все `file:line`-якоря промта сверены грепом на этой машине и сходятся. > **Скоуп — четыре пункта в порядке промта:** (1) ФЧ-5, ось МОДЕЛИ: строка прайсится по модели, которую её стадия резолвит СЕЙЧАС (`Stage.ResolvedModel`); округление вверх при незнании = максимум из цен по ответившей модели, по текущей и — для эскалационных вызовов — по текущему хопу; оговорка «оценка, ошибается вверх, вот чем» в ОБОИХ текстах согласия; обещание точности снимается в `status.go` (комментарий у `RebillUSD`) и в шапке `reprice.go`. (2) Строка 232, остаток «слот»: юнит, который прежний прогон НАЧАЛ (есть строки текущих позиций) и не отгрузил по оси `finalStageWave`, слота гранта повторно не тратит — дописывается вне гранта, считается отдельно. (3) ФЧ-4 обе половины: `rebill_historical_rows` в `status --json` под тем же `rebill_basis` + basis в тексте отказа `--accept-rebill=`; одна формулировка basis для CLI-статуса и текста отказа. (4) ФЧ-1: ровно три названные гарантии — сперва воспроизвести мутацию на копии и увидеть зелень, потом посадка тестом + запись в `cmd/tmmutate/mutations.json`. > **Инварианты:** направление ошибки — никогда не занизить молча (D39.150) · `status` и `translate` — ОДИН вывод · фигура едет с базисом (D39.181 п.1) · ось отгрузки = `finalStageWave`, не draft и не «любая» · схема хранилища, форма манифеста, версия контракта НЕ трогаются · тесты не подгоняются, заказанная смена поведения объявляется (D39.183). > **Не делать:** строки 160 · 221 · 224 · 226 · 228 · 230 · 246 · 247 · 233 · 229 · 141-остаток · 131 · платный замер · новое поле в кадре `finished` шва (класс «поле в опубликованном документе» — ратификация оркестратора; счётчик «дописан вне гранта» живёт в отчёте прогона и логе, вопрос — в отчёт) · коммиты. > **Самопроверка исполнением:** дифф `^func Test` (база 1083, снимок имён снят) · собственные посадки `tmmutate` на копии в scratchpad · свежий адверсариальный проход субагентами Fable 5 (число назову) · `make battery` на копии до и на дереве после. ### 03.09 — ОТЧЁТ пака «число согласия на пути второй покупки» (сессия `textmachine-77`, промт `BACKEND_CONSENT_SESSION_PROMPT.md`) > **Итог:** четыре пункта состава исполнены, дерево `backend/` готово к лендингу, **НЕ КОММИЧУ** (`git diff --cached --name-only` → пусто). HEAD на входе `494c4ef`; после согласованного с платформой (`textmachine-37`) `git pull --ff-only` — **`2a63c37`**. Входящее (72 файла) не пересекалось ни с одним моим файлом, кроме `docs/PROGRESS.md`: свою записку сняла редактором, дала git пройти fast-forward, вернула. Индекс не трогала, stash не применяла. > **Канала к оркестратору нет:** `textmachine-33` в `ListAgents` отсутствует, промт писан на другой машине — вопросы секцией ниже. Все `file:line`-якоря промта сверены грепом здесь и сошлись. > **Батарея на финальном дереве:** `cd backend && make battery` → `MAKE_EXIT=0`, `golangci-lint` `0 issues`, `ok` в 18 пакетах, SKIP: `TestMinerFullBookParity`, `TestHelperEventsRun`, `TestHelperKillLoop`. ⚠ Скипов ТРИ, а не шесть как в базовом прогоне, и это не ослабление: `TestCheckerLabelsBaseline`/`TestCheckerLabelsCandidates`/`TestK6LabelsBaseline` в реальном дереве корпус находят и ИДУТ — `go test ./internal/checks/ -run TestCheckerLabelsBaseline -count=1 -v` → `--- PASS`, `go test ./... -run TestK6LabelsBaseline -count=1 -v` → `--- PASS`. Базовый прогон гнался на копии в `/tmp`, где маркер корня репозитория не находится. > **Тесты `^func Test`:** `grep -rn '^func Test' backend --include=*_test.go | wc -l` → **1083 → 1105**; пофамильный дифф двух снимков (`comm -23`) — **удалённых 0**, добавленных 19. **Комплектность против заказа — по четырём пунктам и по таблице разметки.** **1. ФЧ-5 — ось МОДЕЛИ. Все ЧЕТЫРЕ обязательства D39.150 п.1.** - **(1) прайс по модели, которую стадия резолвит СЕЙЧАС.** `internal/pipeline/reprice.go`, `currentModelFor(stage, escalation)`: для эскалационного вызова — текущий `ResolvedHop`, иначе `ResolvedModel`. **Именно РЕЗОЛВЕННЫЙ слот, а не конфигурационный `model:`** — на книге с лейблами это разные модели, и прайсить надо по той, которую прогон вызовет (пин `TestTheModelAxisReadsTheRESOLVEDSlotNotTheConfiguredOne`, каталожная запись `FC5-model-axis-configured-slot`). Признак эскалации взят из колонки `checkpoints.escalation` полем `store.CheckpointUsage.Escalation`; **схема НЕ тронута** (`git diff --stat -- backend/internal/store/migrate.go` → пусто), колонка живёт с v3. - **(2) округление ВВЕРХ при незнании — формула моя.** `now = max( cost(токены @ модель, которая ОТВЕТИЛА), cost(токены @ модель, которую стадия резолвит сейчас) )`. Довод: количество токенов принадлежит ответившей модели, цена — той, которая ответит; ни одна не смеет опустить число ниже другой. Оба направления проверены исполнением: стадия ушла на модель ×10 — число ×10 (замер приёмки `$0.003640` против `$0.036400` воспроизведён тестом); стадия ушла на модель ÷10 — число НЕ падает. База порога `projectBookUSD` считается тем же `usd()`, поэтому обе половины гейта в одной валюте. - **(3) оговорка в тексте согласия.** `projectionBasis` (`rebill.go`): «…an ESTIMATE that errs upward, never below what the answering model would charge for the same tokens **where their usage is on file**; K of the N unit(s) were **bought from** a model their stage no longer resolves to…». Едет в ЧЕТЫРЁХ операторских местах: пороговый отказ, его scoped-клауза, отказ по названному потолку, и `tmctl status` через `StatusReport.RebillFigureBasis()`. - **(4) обещание точности СНЯТО в ОБОИХ живых местах, названных промтом.** `git grep -n 'can never quote a different number' -- backend/` → пусто; на входном коммите `git grep -n 'can never quote a different number' 2a63c37 -- backend/ | wc -l` → **1** ⚠ (в первой редакции отчёта стояло «3» — число было снято широким грепом на три разных шаблона и приписано этому, узкому; исправлено дофиксом); `grep -rn 'NOT projected (like the content axis' backend/internal` → пусто. Заменено: шапка `reprice.go` — «ROUTING IS PROJECTED, AND IT ROUNDS UP»; комментарий `RebillUSD` в `status.go` — «what neither of them promises is ACCURACY… an estimate that errs UPWARD **where the tokens are known**». Третья копия обещания (исторический комментарий у `projectStoredMemory`) снята попутно. - **Решила сама, сверх буквы заказа:** счётчик `RebillProjection.ModelMovedRows` и поле `rebill_model_moved_rows` в `status --json`. Довод: фигура, часть которой — верхняя оценка через смену модели, без этого числа неотличима от точного пере-прайса, а D39.181 §2.3 требует базиса у опубликованной фигуры. Это ВТОРОЕ новое поле сверх названного промтом одного — вопрос 3. **2. Строка 232, вторая половина — ЗАКРЫТА ТОЛЬКО ПО ОСТАТКУ «СЛОТ».** - **Ось отгрузки — `finalStageWave`**, как велено; не draft и не «любая». Проверена исполнением и на редакторском, и на ЧЕРНОВОМ-ТОЛЬКО конвейере (`TestDeliveryIsReadFromTheSHIPPINGWaveOnADraftOnlyPipeline`, `TestACarriedUnitOnADraftOnlyPipeline`). - **Механизм.** Класс `unitCarried` в `volume.go`: юнит, у которого есть строка ХОТЯ БЫ ОДНОЙ позиции, исполняемой этим конвейером, но не всех, и который не отгружен по оси. Он допускается ВНЕ гранта, но платит; в отчёте — внутри `Delivered` и отдельно в `Carried`. Сравнение с потолком — `granted() = Delivered − Carried + Reworked`, заменило `Paid()` в ОБОИХ местах (`planVolume`, `rescopeEditWave`). - ⚠ **И сам перенос ОГРАНИЧЕН ГРАНТОМ — не больше `MaxUnits` перенесённых за прогон, в порядке книги.** Без этой границы потолок переставал быть потолком: прогон без `--max-units`, начерновивший всю книгу и умерший до редакторской волны, отдавал следующей покупке ВСЕ свои юниты. Замерено на фикстуре: **грант 1 оплачивал 5 юнитов и 5 вызовов провайдера**, а поскольку в остатке не оставалось ничего, прогон не отчитывался вовсе. Найдено адверсариальным проходом по МОЕЙ ЖЕ работе. Принцип границы, а не число: покупка на N может дописать столько же прерванных юнитов, сколько начинает новых, — работа прогона остаётся пропорциональна гранту. Не влезшее держится как `LeftFresh` («никогда не доставлено»), потому что это ровно оно. - ⚠ **`bound()` теперь истинен и когда `Carried > 0`,** а не только когда что-то удержано: прогон, дописавший юниты вне гранта, обязан это СКАЗАТЬ, иначе молчание приходится ровно на случай с наибольшим расхождением. - **Решила сама (промт отдал):** *где вычитается потраченный слот* — нигде: он НЕ БЕРЁТСЯ. *Как переживает рестарт* — носитель «юнит начат» — его же строки `chunk_status` по текущим позициям (`unitStarted`/`unitPositionsOnFile`, одно перечисление с `unitFullyRecorded`, чтобы они не разошлись в понимании «позиции»); схемы не нужно. *Частично двинутый юнит* — carried, дописываются только недостающие позиции. - **Замер строки исправлен:** было «4 купленных юнита → 2 главы», стало 4 → 4 (`TestAUnitInterruptedBetweenWavesTakesNoSecondSlot`: `Delivered=4 Carried=2 LeftFresh=1`, ровно 6 вызовов во второй покупке). - **Семантика `--max-units` изменена и объявлена во всех трёх операторских местах** (`cmd/tmctl/invocation.go`, `Runner.MaxUnits`, `backend/README.md`): грант считает юниты, которые прогон БЕРЁТ СЛОТОМ — новые и пере-делываемые; перенесённые названы в строке стопа и в логе (`finished_from_an_earlier_grant`). ⚠ Тексты НЕ утверждают, что «слот за юнит был взят прежним прогоном»: движок этого не знает (прежний прогон мог идти без потолка), и первая редакция текстов это утверждала — снято. - ⚠ **ОСТАТКИ, которые пак НЕ закрывает — названы в докстринге `deliveredUnits` и здесь:** 1. **«первая редакторская стадия»** (остаток, который промт велел назвать): конвейер, получающий ПЕРВУЮ редакторскую стадию, двигает отгружающую волну с draft на edit, и уже прочитанные юниты репортятся свежими. Закрытие требует записи о том, ЧЕМ БЫЛА отгружающая волна. 2. **Прерванная ПЕРЕ-ДЕЛКА — новый остаток, найденный этим паком.** Отгруженный юнит, чья пере-делка оборвана между волнами, имеет строку в КАЖДОЙ позиции, снова классифицируется `unitRework` и снова берёт слот. Отличить его от обычного банк-онли сдвига (черновик free, редактор пере-оплачивается — определение rework) можно только записью «какой прогон купил какую строку». **Строку 232 закрываю только по остатку «слот», как и велено.** **3. ФЧ-4 — ОБЕ половины, фигура едет с базисом (D39.181 п.1).** - **(а)** `HistoricalRows` больше не теряется на границе `status.go`: `rebillOutcome` возвращает проекцию ЦЕЛИКОМ (под `none`/`failed` — нулевую структуру, так что новое поле не может пережить «неизвестный» ответ, забытое в одной ветке), в `StatusReport` — `rebill_historical_rows` и `rebill_model_moved_rows` под тем же `rebill_basis`. - **(б)** отказ по названному потолку `--accept-rebill=` несёт `projectionBasis(proj)` — базис ТОЙ ЖЕ run-scoped проекции, чьё число печатает. - **Сверх заказа, по тому же правилу «каждая цифра предложения — из его проекции»:** scoped-клауза ПОРОГОВОГО отказа печатала число этого прогона рядом с книжным базисом; теперь несёт свой (`TestTheScopedClauseOfTheRefusalCarriesItsOwnBasis`). Дефект был и до пака. - **Один вывод на два канала:** `StatusReport.RebillFigureBasis()` → строка RE-PAYMENT в `tmctl status`; `TestABilledDecodeRowIsDisclosedAsOldMoneyEndToEnd` сверяет, что проекция, `--json`, CLI и ОБА текста отказа называют одну строку раскрытия. - **Решила сама (промт отдал: имя поля · форма basis · что печатать при `HistoricalRows=0`).** *Имя* — `rebill_historical_rows`, в форме соседей по префиксу `rebill_*`. *Форма basis* — НЕ второе поле-строка рядом с числом, а одна формулировка `projectionBasis`, которую метод `RebillFigureBasis()` переиспользует для CLI: существующий `rebill_basis` остаётся КАЧЕСТВЕННОЙ осью (`pending`/`stored`/`none`/`failed`), а новые счётчики — количественной, и словами их описывает один текст, чтобы гейт и статус не разошлись формулировкой. *При нуле* — печатается ноль, а не пропуск поля: `omitempty` здесь тот же дефект, ради которого его сняли с `rebill_units`/`rebill_usd` — отсутствие поля неотличимо от «свободно». Ноль под `pending` значит «всё пере-оценено», под `failed` — «не считалось»; различает их `rebill_basis`. В операторском тексте при нуле клауза просто не печатается: предложение не должно нести оговорку, у которой нет предмета. **4. ФЧ-1 — ровно три названные гарантии, по каждой все ТРИ шага.** - **Шаг 1 — воспроизвести на копии ДО пака.** `cp -a backend /tmp/.../mut0/backend`, `go run ./cmd/tmmutate -root . -catalog prepack_mutations.json` → **все пять посадок SURVIVED**: фильтр по книге в ОБОИХ пакетах, ключ ячейки без `chunk_idx` в ОБЕИХ формах, снятие пометки «не пере-оценена». ⇒ гарантии (2) и (3), принятые приёмкой СО СЛОВ линзы, подтверждены исполнением; ни одна не оказалась уже прибитой. - **Шаг 2 — посадки тестом.** (1) `TestCheckpointUsageForBookIsScopedToTheBook` (две книги в одной БД, ОДНА позиция) + `TestAnotherBooksMoneyNeverEntersTheConsentNumber`. (2) `TestEveryChunkOfAChapterIsRePricedFromItsOwnCalls` — глава из нескольких чанков РАЗНОЙ стоимости: единственная форма, в которой пул ячейки виден (во всех прежних фикстурах глава = один чанк, потому мутация и переживала). (3) `TestABilledDecodeRowIsDisclosedAsOldMoneyEndToEnd` — продовый путь до `--json`, CLI и обоих отказов. - **Шаг 3 — каталог.** `cmd/tmmutate/mutations.json`: **73 → 92**. Четыре записи `FC1-*` на три гарантии (фильтр по книге пинится в двух пакетах) плюс две `FC5-*` на несущие свойства, которые пак СОЗДАЛ (граница переноса и резолвенный слот) — их я завела по той же логике, по которой каталог существует. Денежный путь в каталоге: греп промта считает СТРОКИ — `git show 2a63c37:backend/cmd/tmmutate/mutations.json | grep -c 'reprice.go\|rebill.go\|volume.go\|ledger.go'` → **0**, тот же греп по дереву → **17**; различных ФАЙЛОВ денежного пути — **0 → 4** (`reprice.go`, `rebill.go`, `volume.go`, `store/ledger.go`). ⚠ В первой редакции стояло «стало 5 файлов» — такого числа не даёт ни одно прочтение; исправлено дофиксом. Прогон всех шести на свежей копии: **6 RED, «0 unexpected outcome(s)», exit 0**. - Четвёртого одноразового харнесса не писала; `tmmutate` гоняла только на копиях в scratchpad. - **Решила сама (промт отдал: форма посадок · уровень теста · текст `why`).** *Форма* — ломать ровно то утверждение, которое гарантия держит, минимальной правкой, и обязательно КОМПИЛИРУЮЩЕЙСЯ: рецепт, оставляющий переменную неиспользованной, даёт `tmmutate` вердикт «ничего не выполнялось», а не «красное», — на этом я поймала два своих же докстринга и переписала их. *Уровень* — по тому, где живёт защита, а не где живёт правка: фильтр по книге пинится и в `store`, и в `pipeline` (мутация пережила обе батареи по отдельности, значит одной мало); ключ ячейки — только `pipeline`, дефект в `newRepricer`; пометка «строка не пере-оценена» — `pipeline`, и именно ПРОДОВЫМ путём, потому что промт называл её не ловящейся на нём. *Текст `why`* — называет СВОЙСТВО и причину, по которой его не видно («во всех прежних фикстурах глава = один чанк»), а не описание правки: `why` читают в тот момент, когда мутация выжила и надо понять, что именно перестало охраняться. **Правки СУЩЕСТВУЮЩИХ тестов — объявляются (D39.183).** - `TestAFlaggedMemberWithNoEditRowIsNotFree` (volume_test.go): описывал «юнит без edit-строки ОБЯЗАН потратить грант» — поведение, которое заказывает пункт 2. Гарантия «не FREE, платит и отчитывается как платящий» СОХРАНЕНА; гарантия «берёт слот» уехала в противоположную. Фикстура расширена до 4 глав; после введения границы переноса ожидание — `Delivered=2 Carried=1 LeftFresh=2`. - `TestAnAnnouncedButFLAGGEDUnitIsStillNewBook`, `TestAUnitWhoseEDITFlaggedIsStillNewBook` (volumedelivery_test.go): флагнутый юнит после добавления стадии теперь carried. Гарантии «анонс ≠ текст» и «судить по ОТГРУЖАЮЩЕЙ строке» сохранены; фикстуры расширены до 3 глав, сигнатуры названных мутаций пере-выведены. ⚠ Рецепты мутаций в их докстрингах были НЕИСПОЛНИМЫ (правка на месте вызова оставляла `shipStages` неиспользованным, пакет переставал собираться, и `tmmutate` дал бы NOTHING вместо RED) — переписаны на правку тела `unitShipped`. - Смена сигнатур (`repriceCheckpoint`/`usd` — третий возврат `moved`; `rebillOutcome` — проекция целиком): `TestRepriceCheckpointFallsBackToTheBilledAmount` (таблица расширена до 11 случаев), `TestRepricerCountsOnlyTheCurrentGenerationOfCheckpoints` (+4 строки), `TestAFailedBasisNeverCarriesAFigure` (сравнивает всю структуру с нулевой — стал строже), `TestRebillConsentCapBelowProjectionRefuses` (+утверждение про базис), **`TestCheckpointsOfOneGenerationSumToTheRowsCost`** (адаптирован под третий возврат `usd()`; ослабления нет, правка механическая — ⚠ в первой редакции отчёта имя пропущено, дописано дофиксом), `reprice_model_test.go` и `render_test.go` (формулировка оговорки: «were answered by» → «were bought from», см. ниже). - `TestStatusPricesTheDriftWithTheGatesOwnNumber` — тронут ТОЛЬКО комментарий, цитировавший снятое обещание. Тест не менялся. - **Удалённых имён — 0.** **Мандат самопроверки — три артефакта.** 1. **Дифф `^func Test` исполнением:** 1083 → 1102, удалённых 0, добавленных 19. 2. **Собственные адверсариальные посадки ВНЕ трёх гарантий:** каталоги `own_mutations.json` (26), `round2_mut.json` (5), `round3_mut.json` (2), `draftonly_mut.json` (2) — **35 посадок**, `tmmutate` на копиях. Итог: **все RED**. ⚠ В первом круге ДВЕ пережили, и это находки: **X21** (`rescopeEditWave` сравнивал грант через `Paid()`, то есть считал перенесённый юнит за слот и отказал бы в свободном) и **X22** (строка стадии, которой конвейер больше не исполняет, засчитывалась как «юнит начат»). Обе прибиты (`TestTheRePlanCountsSlotsNotCarriedUnits`, `TestRowsOfARetiredStageAreNotAStart`) и во втором круге RED. 3. **Проход по СВОЕЙ готовой работе свежим контекстом.** Воркфлоу из семи линз (направление ошибки · раскрытие на новой границе · слот и черновой конвейер · вывод членства `usd()` · правда текста · качество тестов · скоуп и заказ), каждая находка судится тремя независимыми опровергателями (корректность · воспроизведение · сверка с промтом), большинство решает. Модели: линза качества тестов — Fable 5, остальные — Opus 5 (ограничение владельца на число Fable-агентов соблюдено: один). **Числа прохода: 7 линз, 27 находок (2 HIGH · 12 MED · 13 LOW), 42 вердикта верификаторов, 46 агентов.** ⚠ Верификаторов «подтверждено» — НОЛЬ, и читать это надо точно: фаза верификации шла по дереву, где все 27 находок были уже исправлены, то есть опровергатели подтверждали ПРАВКИ, а не отсутствие дефектов. Каждая находка ниже воспроизведена или прочитана мной по коду до правки. **Находки и диспозиции (все ИСПРАВЛЕНЫ, каждая с посадкой):** - **[HIGH] перенос без границы обнулял потолок** — грант 1 оплачивал 5 юнитов, и прогон об этом молчал. Введена граница `Carried ≤ MaxUnits` + `bound()` по `Carried`; посадки `FC5-carry-unbounded` и `FC7-volume-stop-silent-outside-grant` (в первой редакции вторая называлась разведочным именем `Y2-silent-when-nothing-left`, которого в каталоге нет — переименовано дофиксом, Б7). - **[MED] `reconcile` мог вывести `Delivered` ниже `Carried`** — `granted()` уходил в минус, строка стопа говорила «0 NEW unit(s) delivered (1 of the new ones had been started…)», предложение, которое не может быть истинным. Все ветви теперь держат вложенность; посадки `FC7-reconcile-free-branch` и `FC6-reconcile-fresh-branch` (в первой редакции стояло разведочное `Y3`, которого в каталоге нет — переименовано дофиксом, Б7). - **[MED] операторские тексты утверждали «слот за юнит был взят прежним прогоном»** — движок этого не знает. Снято во всех трёх местах. - **[MED] ось модели не была прибита на РЕЗОЛВЕННОМ слоте** — чтение `st.Model` вместо `st.ResolvedModel` переживало весь пакет. Пин + каталожная запись `FC5-model-axis-configured-slot`. - **[MED] $0-строка без usage под сдвинутой стадией** публиковалась как $0 без оговорки. Теперь помечается «не удалось пере-оценить»; посадка `FC7-zero-usage-row-silent-after-a-move` (в первой редакции — разведочное `Z2`). - **[MED] scoped-клауза порогового отказа шла без своего базиса** (дефект был и до пака) — исправлено, посадка `FC7-scoped-clause-without-basis` (в первой редакции — разведочное `X29`). - **[LOW] ветка отката (`overshoot`) причисляла строку к «пере-прайсенным по сдвинутой модели»**, хотя цитирует БИЛЛЕННУЮ сумму, не прайсенную ни по одной сегодняшней таблице. `moved` там снят; посадка `FC7-overshoot-claims-a-model-move` (в первой редакции — разведочное `Y4`). - **[LOW] `moved` считается против `ModelRequested`, а пять текстов говорили «модель, которая ОТВЕТИЛА»** — на провайдере, канонизирующем слаг (`gpt-5-mini` → дата), это разные вещи. Код верен (пере-прогон запросит модель стадии), тексты приведены к нему. - **[LOW] комментарий про `zeroRow` утверждал, что хвост $0-вызовов — ОДНО поколение.** Это неверно: $0-стадия оставляет `cost_usd == 0` после каждого прогона, поколения неразличимы, и число может быть кратным. Направление при этом ратифицированное (вверх), и оговорка «errs upward» его покрывает; ложное утверждение из комментария снято, ограничение названо вслух. - **[LOW] комментарий про redrive** утверждал, что пере-атакованный юнит «начинается заново». Неверно: `ResetChunkStages` удаляет только FLAGGED и SKIPPED стадии, черновая `ok`-строка остаётся, и юнит остаётся carried. Комментарий приведён к коду. - **[LOW] доки кадра `finished`** (`runevents.VolumeLedger`) отправляли читателя к полю `Free` за объяснением «почему юнитов больше, чем грант», хотя теперь причина может быть и в `Delivered`. Тексты исправлены; **поля на провод НЕ добавлено** — вопрос 1. В `runevents/` изменены ТОЛЬКО комментарии (проверено: дифф без строк кода), `StreamVersion` не тронут. - **[LOW] докстринг `CheckpointUsageForBook` ссылался на несуществующий id каталога** `FC1-book-filter` (в каталоге две записи, `-store` и `-pipeline`); `tmmutate -id` матчит точно, и следующая сессия получила бы «ничего не выбрано». Исправлено. - **[LOW] комментарий у `RebillHistoricalRows` называл платформу потребителем поля** — её аллоулист не берёт ни одного `rebill_*`. Формулировка приведена к факту: потребитель — операторская оснастка, читающая документ; платформа поле игнорирует. - **[LOW] несколько комментариев рассказывали ИСТОРИЮ починки** («used to», «went stale once already», «is how four bought units became two chapters») вместо описания кода — закон владельца. Переписаны; провенанс оставлен только в докстрингах ТЕСТОВ, где он в зоне принят. - **[LOW] «первая половина» текста согласия обещала «never below…» без оговорки** про строки, которые пере-оценить не удалось: они как раз могут стоять НИЖЕ сегодняшней таблицы. Добавлено «where their usage is on file» и «may sit below today's table». **Три оси ревью, названные промтом уязвимыми именно в этом паке — по каждой предъявляю.** 1. **Направление ошибки.** Двойной счёт искала специально: порог сравнивает базу и сумму, посчитанные ОДНИМ `usd()` (тест сверяет `projected_book_usd`, а не только сумму), максимум из двух цен берётся РОВНО один раз на вызов, добавка денег банк-ролей входит в опубликованную проекцию и НЕ входит в базу порога — как ратифицировано. Перелёт порога проверен с обеих сторон: число выросло там, где занижало, и не упало там, где стадия ушла на дешёвую модель. Одну форму двойного счёта ревью всё же нашло — кратность оценки $0-строки; направление у неё безопасное (завышение), ограничение названо вслух и в коде, и в секции «не проверено». 2. **`HistoricalRows` на новой границе.** Не теряется и не удваивается: единственный инкремент на строку, `rebillOutcome` отдаёт проекцию целиком, под «неизвестно» — нулевую структуру. Текст отказа и `--json` называют ОДНО число с ОДНИМ базисом — это утверждает тест, сравнивающий подстроку `RebillFigureBasis()` внутри текста отказа, а не два независимых ожидания. 3. **Слот гранта на черновом-только конвейере.** Проверено исполнением, а не рассуждением: `TestACarriedUnitOnADraftOnlyPipeline` — ось не выродилась в «никогда ничего не отгружено» (юнит, начатый и не отгруженный, опознаётся и дописывается), и не выродилась в обратную сторону (уже отгруженные не пере-продаются — `TestDeliveryIsReadFromTheSHIPPINGWaveOnADraftOnlyPipeline`). **Что НЕ удалось и что НЕ проверено.** - **Остаток «первая редакторская стадия»** — вне скоупа, требует носителя прошлой отгружающей волны (схема). - **Остаток «прерванная пере-делка»** — найден этим паком, требует записи «какой прогон купил какую строку» (схема). - **Кратность оценки $0-строки:** книга, у которой $0-стадия пере-куплена N раз, а потом уведена на платную модель, получает оценку, кратную N. Направление безопасное (завышение) и объявлено в тексте согласия, но точным его не сделать без маркера поколения на `checkpoints` — та же схемная развилка, что в докстринге `usd()`. - **Юнит, начатый НЕОГРАНИЧЕННЫМ прогоном,** слота в следующем ограниченном не берёт (но перенос ограничен грантом). Замерено тестом, на живой книге не проверялось. - **Взаимодействие переноса с ДЕНЕЖНЫМ потолком** на длинном хвосте начатых юнитов не замерено: по построению объёмный потолок их не считает, держит денежный. - **Живой прогон с платными вызовами не делался** — промт его не заказывал. Вендор-сверок нет: пак не трогает слаги моделей. **⚠ Якоря в ЧУЖИХ доках, уехавшие ИЗ-ЗА пака — править не могу, зона не моя; вот готовый список с новыми номерами** (`python3 docs/scripts/counts.py --lint`; все шесть были ЦЕЛЫ на HEAD `2a63c37`, проверено `git show HEAD:<файл> | sed -n 'p'`): | док:строка | якорь был | цель сейчас | |---|---|---| | `docs/architecture/15-money-path.md:18` | `store/ledger.go:381` «SpentUSD reports (committed, reserved)» | `:392` | | `docs/architecture/15-money-path.md:24` | `pipeline/status.go:290` «book_ceiling_usd,omitempty» | `:311` | | `docs/architecture/15-money-path.md:24` | `pipeline/status.go:788` «100 * (committed + reserved)» | `:811` | | `docs/PROGRESS.md:179` (тело строки 232) | `pipeline/status.go:866` «IT IS NO LONGER THE READ PATH'S FIRST ANSWER» | `:901` | | `docs/archive/prompts/BACKEND_CONSENT_SESSION_PROMPT_2026-09-02.md` (строка 52 на момент выдачи; в архиве номера сдвинул баннер исхода) | `pipeline/status.go:217` «can never quote a different number» | **снят по заказу (ФЧ-5 п.4)** | | `docs/archive/prompts/BACKEND_CONSENT_SESSION_PROMPT_2026-09-02.md` (строка 54 на момент выдачи) | `pipeline/reprice.go:24` «NOT projected (like the content axis» | **снят по заказу (ФЧ-5 п.4)** | Первые четыре — сдвиг номеров от моих вставок; последние два промт заякорил на тексте, который сам же велел снять, поэтому их «поломка» и есть признак исполнения. ⚠ **Про остальные 12 я сперва написала здесь «все в `docs/experiments/**`, пришли с полигонным мержем» — это было неверно, и поправлено разбором с платформенной сессией.** Перечисляю по владению; ⚠ **общее число гейта — величина ПОДВИЖНАЯ**, обе смены правят дерево параллельно: на момент того разбора `python3 docs/scripts/counts.py --lint` печатал 18, на момент сдачи дофикса — **20** (в отчёте пака стояло «все 18 строк», и это было верно только для того часа). Разбивка по владению взята с той, 18-строчной выдачи: - **4 — платформенной сессии** (`textmachine-37`): `docs/PROGRESS.md:19`, `docs/archive/prompts/PLATFORM_P13_SESSION_PROMPT_2026-09-02.md` (строка 286 на момент выдачи) и `docs/archive/prompts/BACKEND_CONSENT_SESSION_PROMPT_2026-09-02.md` (строка 227 на момент выдачи) целятся в одну снятую ею строку рантбука `platform/deploy/README.md:213` «сначала платформа, потом движок»; плюс `docs/archive/prompts/PLATFORM_P13_SESSION_PROMPT_2026-09-02.md` (строка 166 на момент выдачи) на уехавший `Quarantine`. ⚠ Третий из них живёт В МОЁМ промте (это его ⛔-оговорка о том, что совет рантбука опасен), но сломан не мной — целью владеет платформа. - **8 — полигонных**, пришли с мержем `2a63c37`: семь в `docs/experiments/**` и один в теле бэклога — `docs/PROGRESS.md:190` на `eval/conformance.py:48`. - ⚠ Якорь в `docs/experiments/23-editor-tier.md:6196` целится в строку 679 этого журнала, которой в нём нет: он был мёртв и до пака (тогда в файле было 472 строки), а мои вставки лишь меняют общее число, которым гейт объясняет смерть. ⚠ Записан здесь СЛОВАМИ, без токена «путь:номер» в обратных кавычках: гейт читает такой токен как якорь, и первая редакция этой строки сама добавила себе двадцатую поломку. **Урок, который стоит записи:** первую версию этого абзаца я построила на подсчёте, не перечислив предмет, — тот же класс, что и мои прошлые ошибки «вывести отсутствие из счёта». Счёт по подстроке пути (`grep -c 'platform/'`) тоже не есть счёт по владению: у платформы один из четырёх якорей целится ОТНОСИТЕЛЬНЫМ путём и в такой счёт не попадал. **Вопросы, вынесенные владельцу, и его слово (03.09) — записываю, чтобы решения не пере-открывались.** 1. **Поле `carried` в кадре `finished` шва** (`runevents.VolumeLedger`). Спрошено: добавлять ли число «сколько глав дописано сверх гранта», ведь `delivered` теперь может превышать `max_units`. Цена вопроса названа: это класс «новое поле в опубликованном документе» — ратификация оркестратора плюс минорный бамп `StreamVersion`, а промт запретил двигать контракт; платформа кадр `Volume` сегодня не декодирует вовсе (`platform/internal/ingest/events.go`: `Finished{Outcome}`), потребителя у факта нет. **РЕШЕНИЕ ВЛАДЕЛЬЦА: оставить как есть, поле не добавлять.** Исполнено: поля нет, объяснение живёт словами в докстрингах `Delivered` и `Free` того же кадра. 2. **Семантика «юнит, начатый прогоном БЕЗ объёмного потолка, слота в следующей покупке не берёт; перенос ограничен размером гранта».** Альтернативы названы: тратить на такие юниты купленное (тогда покупатель платит за главу дважды — ровно вред строки 232) либо завести схемный носитель «какая покупка оплатила какую строку». **СЛОВО ВЛАДЕЛЬЦА: вынести оркестратору, решение отложено — «подумаем на этот счёт».** ⇒ пункт остаётся ОТКРЫТЫМ вопросом к приёмке; в коде сейчас первый вариант, ограниченный грантом. 3. **`rebill_model_moved_rows`** — второе новое поле `status --json` сверх названного промтом одного; говорит, какая часть суммы завышена из-за смены модели стадии. Аддитивно, платформой игнорируется (её аллоулист не берёт ни одного `rebill_*`); без него человекочитаемая строка и текст отказа перестают говорить дословно одно и то же. **РЕШЕНИЕ ВЛАДЕЛЬЦА: оставить.** 4. **Ошибок в промте не нашла.** ### 03.09 — ДОФИКС по приёмке №22 (наряд `docs/archive/prompts/BACKEND_DOFIX_2026-09-03.md`, сессия `textmachine-77`) > **Состояние git на входе в дофикс — важнее прочего, потому что наряд писан по другому.** Наряд говорит «в индексе лежит незакоммиченная работа двух смен». К моменту исполнения владелец уже закоммитил её в ЛОКАЛЬНЫЙ `e85295d` «temp», а `origin/main` был обновлён ПРИНУДИТЕЛЬНО на `ea54355`, в историю которого `temp` не входит (`git merge-base --is-ancestor e85295d origin/main` → нет). По слову владельца я откатил temp и подтянул наряды двумя командами: `git reset --mixed 2a63c37`, затем `git merge --ff-only origin/main` (перемотка — `ea54355` растёт из того же `2a63c37`). Перед этим поставил метку **`temp-backup-e85295d`**, чтобы коммит с работой обеих смен нельзя было потерять; снимать её до лендинга не надо. Целостность проверена, а не предположена: изменённые файлы совпали с temp **бит-в-бит** (сравнение хешей двух диффов), пять добавленных файлов снова стали неотслеживаемыми и лежат на диске побайтно как в коммите (`git hash-object` против `git rev-parse e85295d:<файл>`). В дереве НА МОМЕНТ ОТКАТА было 44 файла: 22 мои, 21 платформы, один общий журнал; дальше число растёт у обеих смен по мере работы. **Индекс пуст, не коммичу.** > > **Батарея после дофикса:** `cd backend && make battery` → `MAKE_EXIT=0`, `golangci-lint` ``0 issues``, `ok` в 18 пакетах, SKIP: `TestMinerFullBookParity`, `TestHelperEventsRun`, `TestHelperKillLoop`. > **Тесты `^func Test`:** `grep -rn '^func Test' backend --include=*_test.go | wc -l` → **1083 → 1105** (пак довёл до 1102, дофикс и правки по проверяющему добавили остальное), удалённых **0** (`comm -23` по снимкам имён). > **Каталог `cmd/tmmutate/mutations.json`:** **73 → 92** (`python3 -c "import json;print(len(json.load(open('backend/cmd/tmmutate/mutations.json'))))"`), прирост **19** записей: паком **6** (`FC1`×4 — три названные гарантии, `FC5`×2 — свойства, которые пак создал), дофиксом и разбором его проверки **13** (`FC6`×4, `FC7`×5, `FC8`×3). ⚠ В первой редакции этой строки стояло «18 заведено дофиксом и проверкой», а перечень в скобке давал 14 и не называл `FC1` — число одной величины под именем другой, тот же класс, что чинит Б8. Команда: `python3 -c "import json;from collections import Counter;d=json.load(open('backend/cmd/tmmutate/mutations.json'));print(Counter(m['id'].split('-')[0] for m in d if m['id'][:3] in ('FC1','FC5','FC6','FC7','FC8')))"`. **По каждому пункту Б1–Б9.** **Б1 — стоп-строка и лог лгали в случае, который пак создал. ЗАКРЫТО.** Воспроизвёл сам, до правки: `VolumeStop{MaxUnits:2, Delivered:2, Carried:2}` → `Left()=0 granted()=0 Paid()=2`, и предложение печатало разом «not on money and **not at the end of the book**» и «Still in the book: **0** unit(s) NEVER delivered». Правка: у `String()` теперь ДВА открытия по `Left()`. Грант придержал работу → прежний текст. Книга кончилась → «reached the END of the book under a VOLUME ceiling (--max-units N), which held nothing back», и хвост «Nothing is left in the book» вместо перечисления нулей. Смешанный случай отдельного текста не требует: это первая ветка с уже существующей клаузой про перенесённые. Тот же развилкой пошёл лог `waverun.go` (сообщение выбирается тем же предикатом), а протухший комментарий у `scope.bound()` пере-написан на то, что код делает: «set when the grant held work back OR when the run did work outside it». Пин: `TestARunThatWorkedOutsideItsGrantSaysSo` дополнен — требует и «reached the END of the book», и «Nothing is left in the book», и ЗАПРЕЩАЕТ «not at the end of the book». **Б2 — ратифицированный контракт кадра `finished.volume` стал ложным. ЗАКРЫТО, поля НЕ добавлял.** Утверждение «present only when a volume grant actually held work back» снято во всех ЧЕТЫРЁХ местах: `runevents.go` (объявление поля и абзац «its PRESENCE is the boolean»), `events.go` (`volumeLedger`), `bookrun.go` (`BookResult.Volume`). Проверка: `grep -rn 'only when the grant actually held something back\|present only when a volume grant actually held\|nil when no grant held anything back\|rather than because the book ended' backend/internal` → пусто. Новая формулировка говорит, что присутствие значит «грант был в силе и прогону есть что о нём сказать», и что различают два случая `left_fresh`/`left_rework` — оба ноля значат «книга кончилась». Там же прямо сказано, что счётчика перенесённых на проводе НЕТ и почему: владелец 03.09 сказал «оставить как есть». Ратификационная ссылка сохранена с оговоркой, что правило присутствия расширилось вместе со строкой 232. **Б3 — три свойства не были прибиты. ЗАКРЫТО, каждое воспроизведено и посажено.** Сначала воспроизвёл все три на копии — **все три SURVIVED**, как и писала приёмка. После правки те же три посадки на свежей копии → **все три RED**. - **(а)** ветка `unitFresh` в `reconcile`: новый `TestReconcileKeepsContainmentOnTheFreshBranch`. ⚠ Состояние в нём СКОНСТРУИРОВАНО, а не наблюдено, и это сказано в докстринге: `Delivered == Carried` с исходом класса `unitFresh` не даёт сегодня ни одна фикстура. Утверждаю инвариант всё равно, потому что код заявляет его для КАЖДОЙ ветки. - **(б)** отказ по названному потолку: `TestTheScopedClauseOfTheRefusalCarriesItsOwnBasis` дополнен половиной про `--accept-rebill=` — требует «1 of the 1» и запрещает «2 of the 2». - **(в)** оговорка про смену модели при нуле: `TestProjectionBasisNamesWhatTheAmountIsMadeOf` получил отрицательный пин, симметричный тому, что был у близнеца про старые деньги. Записи каталога: `FC6-reconcile-fresh-branch`, `FC6-capped-refusal-borrows-book-basis`, `FC6-model-caveat-printed-at-zero`. **Б4 — докстринг `classifyUnits` не пере-считан. ЗАКРЫТО.** «three things this run can do to it» → «four»; проверено, что членов `unitClass` действительно четыре (`sed -n '/^const (/,/^)/p' … | grep -c '^\tunit'` → 4). **Б5 — пример в `README.md:73` противоречил новой семантике. ЗАКРЫТО.** «оплатить не больше 10 выходных юнитов» → «не больше 10 выходных юнитов возьмут слот», в согласии с телом README:11. **Б6 — шов `store → репрайсер` прибит с одной стороны. ВЗЯЛ, хотя пункт «по желанию».** Довод: мой же аргумент по фильтру книги («мутация пережила обе батареи по отдельности, значит одной мало») применим и здесь, и отказ от него был бы непоследовательностью, а не решением. Новый `TestCheckpointUsageCarriesTheEscalationFlag` в `internal/store` + запись `FC6-escalation-flag-store`; подмена `c.escalation` на `0` теперь краснеет и в store-пакете. **Б7 — отчёт ссылался на ПЯТЬ несуществующих посадок как на живые гейты. ЗАКРЫТО заведением, а не снятием ссылок.** Проверил каждую из пяти на копии: **все пять ловятся существующими тестами** — то есть свойства охраняются, но каталог их не помнил, а отчёт называл гейтами. Развязка честная только одна: сделать их настоящими записями. Заведены `FC7-volume-stop-silent-outside-grant`, `FC7-reconcile-free-branch`, `FC7-zero-usage-row-silent-after-a-move`, `FC7-scoped-clause-without-basis`, `FC7-overshoot-claims-a-model-move`; все пять пере-посажены → RED. **Б8 — четыре числа не печатались командами, которые отчёт для них называл. ЗАКРЫТО, каждое пере-считано.** - «денежного пути стало 5 файлов» — такого числа не даёт ни одно прочтение. Правда: греп промта считает СТРОКИ, `0 → 17`; различных ФАЙЛОВ денежного пути `0 → 4`. Обе команды вписаны рядом с числами. - «на входе 3 попадания» у грепа про снятое обещание — правда **1**: `git grep -n 'can never quote a different number' 2a63c37 -- backend/ | wc -l` → 1. Тройка была снята широким грепом на ТРИ разных шаблона и приписана этому, узкому. Тот же класс, что и мои прошлые ошибки со счётом: число из одной команды под именем другой. - «все 18 строк» линта — на момент сдачи дофикса гейт печатает **20** (`python3 docs/scripts/counts.py --lint`). Число ПОДВИЖНОЕ: параллельная платформенная смена правит свои файлы, и её якоря уходят и возвращаются. В отчёт пака вписана оговорка об этом. - «в файле 485 строк» — сейчас **572** (`wc -l < docs/PROGRESS.md`); число снималось до того, как отчёт дорос, и с каждой вставкой меняется. Формулировка в отчёте пака переписана так, чтобы не зависеть от него. - ⚠ **Отчёт пака сам добавлял себе поломку гейта:** строка таблицы называла чужой мёртвый якорь ТОКЕНОМ «путь-двоеточие-номер» в обратных кавычках, и гейт читал её как якорь ЭТОГО журнала. Переписана словами. ⚠ И первая редакция этого самого пункта наступила на то же место второй раз — объясняя поломку, она снова процитировала токен и снова его создала. Теперь ни одна строка обеих моих записей токена не содержит; проверка — грепом по выдаче гейта на строки этого журнала в моих секциях, пусто. **Б9 — неполнота самообъявления по D39.183. ЗАКРЫТО.** `TestCheckpointsOfOneGenerationSumToTheRowsCost` дописан в блок самообъявления: адаптирован под третий возврат `usd()`, ослабления нет, правка механическая. **Б10 — к сведению, не заказ; называю, чтобы не умерло молча.** - **Подсказка в докстринге `Delivered` ключуется на `delivered > max_units`,** а в форме «весь остаток перенесён» `delivered == max_units` — подсказка не срабатывает, и разложить кадр читателю нечем. Связано с отложенным вопросом владельца о семантике переноса; чинится вместе с ним. - **В перенос попадает и юнит, который ФЛАГНУЛСЯ и текста не отдал:** он «начат и не отгружен», значит следующая покупка снова платит за его пере-атаку вне гранта. Цикл из трёх последовательных покупок не гонял никто — ни приёмка, ни я. Вход в решение владельца, не дефект. **Проверка дофикса свежим контекстом — один агент Fable 5, ограничение владельца соблюдено.** Он прочитал исходный промт, наряд, оба моих отчёта и весь дифф, посадил 26 своих мутаций и пере-гнал батарею на копиях. Из его семи находок **три взяты в работу и исправлены**, четыре названы ниже как известные пробелы: - **[HIGH] `$0`-вызов ВНУТРИ платного поколения выпадал из обхода** — и уносил с собой сегодняшнюю цену. Форма: черновая стадия на локальной `$0`-модели с ПЛАТНЫМ `escalate_to`; стоимость строки объясняет один хоп, поэтому обход останавливался и бесплатный primary терялся, а после сдвига стадии на платную модель число согласия выходило вдвое ниже реальной пере-покупки, БЕЗ оговорки. Воспроизвёл сам на юнит-уровне до правки: `usd=0.010000 fromHistory=false moved=false` при пере-покупке `0.03`. Правило переписано: **вызов, стоивший ноль, никогда не останавливает обход и никогда не переполняет счёт** — он берётся всегда, а обход стоит на первом ПЛАТНОМ вызове после того, как деньги строки объяснены. Цена решения названа в коде вслух: бесплатный вызов на хвосте СТАРОГО поколения тоже будет взят, то есть оценка завышается — ратифицированное направление. Посадка `FC8-free-call-dropped-from-a-paid-generation`. - **[LOW→взято] `$0`-строка, чей новейший вызов чужой,** котировалась `$0` без оговорки: переполнения на нуле не бывает, поэтому детектор отката её не видел. Теперь такая строка помечается «не удалось пере-оценить»; `skipped`-строка остаётся честно бесплатной. Посадка `FC8-unestablished-zero-row-published-as-free`. ⚠ Существующий случай таблицы, чей комментарий говорил «skipped-строка», диспозицию не ставил — привёл тест к его собственному замыслу и добавил случай без скипа (объявляю по D39.183: поведение сменилось по находке, тест стал строже). - **[LOW→взято] развилка ЛОГА из Б1 не была прибита** — мутация «удалить ветку конца книги» переживала весь пакет. Новый `TestTheRunLogSaysWhichKindOfVolumeStopItWas` (обе ветки, живым прогоном), посадка `FC8-log-fork-at-the-end-of-the-book`. - **[MED→исправлено] отчёт пака называл пять посадок разведочными именами** (`Y2…`, `Y3`, `Z2`, `X29`, `Y4`), которых в каталоге нет: Б7 завёл их под именами `FC7-*`, но ссылки остались старыми. Переименованы; `grep` по каталогу на старые имена → 0, ни одно из них больше не стоит в отчёте как имя гейта. **Второй проход того же проверяющего — по трём осям, вердикт его словами.** Дерево ему было пере-сдано после правок; он адресно пере-атаковал свои находки 1, 3 и 6 (все три ДЕРЖАТ, каталожные посадки красные), отдельно проверил новое правило обхода `usd()` таблицей краевых форм (откат, остаток, эскалационный хоп, `skipped`, нулевая стоимость) и занижений не нашёл. **A — исходный промт: исполнено с остатком** (остатки — два схемных остатка строки 232 и отложенный вопрос владельца, все названы и заказаны такими). **B — наряд Б1–Б9: все девять закрыты** (Б8 был закрыт с остатком, см. N1 ниже — закрыт). **C — код и отчёты: ГОДНО К ПРИЁМКЕ, блокеров нет.** Три его новые находки, все LOW, закрыты здесь же: - **N1** — строка отчёта говорила «18 заведено дофиксом и проверкой», а раскладка в скобке давала 14 и не называла `FC1`. Правда: прирост 18 = паком 6 (`FC1`×4, `FC5`×2) + дофиксом и разбором проверки 12 (`FC6`×4, `FC7`×5, `FC8`×3). Тот же класс, что чинит Б8, — число одной величины под именем другой; пере-считано командой, она стоит рядом. - **N2** — условие `len(calls) > 0` в метке «поколение не установлено» не было прибито: мутация переживала пакет. Добавлен случай «`$0`-строка без единого вызова на файле свободна, а не нераскрыта» + запись `FC8-empty-cell-disclosed-as-unestablished` (красная). - **N3** — комментарий у той же ветки описывал `skipped`-строку так, будто guard несущий, тогда как продовые вызывающие skipped-строки сюда не доводят (`projectRebill` их отфильтровывает, `projectBookUSD` роняет флаг). Комментарий говорит теперь ровно это: guard защитный, а не несущий, и почему он остаётся. Его диспозицию по находкам 4 и 5 («согласен, входы в отложенный вопрос владельца») принимаю; он же заметил, что находку 4 можно закрыть и без смены семантики — снимком plan-time `Carried`. Это ВЫБОР, не необходимость, и он входит в тот же вопрос владельца. **Что НЕ удалось и что НЕ проверено (дофикс).** - **Цикл из трёх покупок на флагнутом юните** не замерен — см. Б10. Знаю, что не проверено; не чинил, потому что наряд прямо запретил трогать семантику переноса. - **Состояние `Delivered == Carried` с исходом класса `unitFresh`** (Б3а) ни одной фикстурой не достигается; инвариант утверждён на сконструированном состоянии, и это сказано в самом тесте. - **Живого прогона с платными вызовами не было** ни в паке, ни в дофиксе. - **Оба остатка строки 232** (первая редакторская стадия; прерванная пере-делка) по-прежнему открыты и требуют схемного носителя. - **Четыре находки проверяющего названы, но НЕ чинятся — все четыре суть входы в отложенный владельцем вопрос о семантике переноса, и наряд прямо запретил её трогать:** 1. Клауза «finished OUTSIDE this grant» ключуется на `Carried` ПОСЛЕ `reconcile`, поэтому исчезает, когда все перенесённые юниты флагнулись: оператор видит «2 PAID FOR BUT FLAGGED», но не то, что обе оплаты шли вне гранта. Воспроизведено: `VolumeStop{MaxUnits:2, Delivered:2, Carried:2}` + два флага класса `unitCarried`. 2. Перенесённый юнит с ПРОТУХШИМИ черновыми строками пере-покупает всю цепочку вне гранта, тогда как хелп флага обещает «дописать недостающее». Воспроизведено проверяющим: `granted()=0`, два вызова провайдера на один юнит. 3. Подсказка в докстринге `Delivered` ключуется на `delivered > max_units` и молчит в форме «весь остаток перенесён», где `delivered == max_units` (это же Б10 наряда). 4. Цикл из ТРЁХ последовательных покупок на флагнутом юните не гонял никто — ни приёмка, ни проверяющий, ни я. - **Выживание трёх гарантий ФЧ-1 на дереве ДО пака** проверяющий сам не воспроизводил (принял по моим красным посадкам); я это делал в паке отдельно, лог в scratch-каталоге сессии. ### 05.09 — ОТЧЁТ пака «денежный стоп перестаёт быть аварией» (сессия `textmachine-main-be`, промт `BACKEND_MONEYSTOP_SESSION_PROMPT.md`) > **ПОЛНЫЙ ОТЧЁТ — `backend/docs/MONEYSTOP_REPORT.md`** (происхождение решений, пять рисков зоны по > одному, самопроверка, объявления по D39.183, obstacle reporting). Здесь — итог и то, что нужно > оркестратору для лендинга. **Дерево НЕ закоммичено.** > > ⚠ **В дереве лежат ЧУЖИЕ правки — вся `platform/`** (параллельный пак `textmachine-main-63`). Не > тронуты ни байтом. **Платного прогона НЕТ**: все три оси предъявлены за $0. **Четыре пункта закрыты.** (1) строка **271** — правки банка больше не могут писать свои строки внутрь system-сообщения платного вызова: одна граница (`internal/membank/wirefence.go`), три точки исполнения — дверь отказывает, загрузчик сида отказывает, рендереры пропускают; предел 200 рун, запрет Cc + U+2028/9 + bidi-переопределений (Trojan Source), при этом ZWJ/ZWNJ/LRM/RLM РАЗРЕШЕНЫ (общность §0.1); фолд версии СКОУПНЫЙ, чистая книга хеширует байт-в-байт как до фикса — запинено значением, снятым сборкой `32be78a`. (2) строка **277** — отказ резерва защёлкивает волну и не отменяет допущенное; отказ не окончателен при непустом полёте (ждём settle, повторяем тот же резерв); только ОБЯЗАТЕЛЬНЫЕ вызовы ждут. (3) строка **278** (событие) — недостача едет в `ceiling`, `StreamVersion` 1.2 → 1.3, денежный леджер в `finished`. (4) строка **278** (проекция) — цена книги ДО покупки в `manifest --json` и `status --json`. **Числа, каждое получено командой (полный список — §6.7 отчёта).** ⚠⚠ **ТРИ ИЗ НИХ ПРОТУХЛИ ЧЕРЕЗ ТРИ ЧАСА, И ОДНО ПЕРЕВЁРНУТО — поправка в конце абзаца; она найдена ВЕРИФИКАТОРОМ 05.09, не зоной и не мной:** тестовых функций **1172 → 1208 (+36)**, все тридцать шесть в трёх новых файлах; `git diff -U0 -- backend | grep -E '^[+-]func Test'` ПУСТ — ни одна существующая не удалена и не переименована, два протухших починены внутри тела. Каталог мутаций **158 → 191**. Батарея: `MAKE_EXIT=0`, 19 пакетов, 0 упавших, 0 issues (шестой прогон — первые пять красны или остановлены). Каталог ЦЕЛИКОМ: **191 запись, 187 RED, 0 SURVIVED, 0 NOTHING, 0 ROTTED, 0 неожиданных исходов** — второй полный прогон; ПЕРВЫЙ не сошёлся и нашёл четыре дефекта в моих же артефактах, включая named-артефакт приёмки (§6.5 отчёта) (и `go vet -vettool` собственного анализатора зоны — чисто; он поймал у меня один хенд-билд `config.Stage`, см. отчёт). ⚠⚠ **ПОПРАВКА 05.09 (замер верификатора по дереву на `d766007`; числа выше НЕ переписаны — они были верны в свою минуту).** Абзац заленджен коммитом `ba4fd34` через **девять секунд** после пака `81a89e9` и за **три с лишним часа ДО** дофикса `616a8e4`, который добавил ещё +5 тест-функций и +10 записей каталога. Сообщение коммита подписало их «final counts», и после дофикса их никто не тронул. Верно на сегодня: тестовых функций **1172 → 1213 (+41)** · каталог мутаций **158 → 201** · каталог целиком — **201 запись, 197 RED, ЧЕТЫРЕ аргументированных выживших, 0 неожиданных исходов**. ⛔ **⚠ **Испр. 06.09 автором находки: ПРОТУХЛИ ДВА числа, не три, и „0 SURVIVED" НЕ протухло.** У инструмента ДВА ведра: `SURVIVED` — **неожиданный** выживший (настоящая дыра), `survives` строчными — записанный и аргументированный. На ревизии, которую абзац описывает, каталог был 191 = 187 red + 4 survives, то есть все три числа верны ДЛЯ СВОЕЙ РЕВИЗИИ; четыре аргументированных были четырьмя уже тогда. Протухли 191→201 и 187→197. Третье — не протухание, а НЕПОЛНОЕ ПЕРЕЧИСЛЕНИЕ: 187+0+0+0 = 187 при собственном итоге 191, потому что ведро аргументированных не названо. Дефект другой природы и слабее. Прежняя редакция: **Переворачивается именно последнее: «0 SURVIVED» против четырёх записанных выживших** — а это то самое различение из `D39.202` п.3 (`SURVIVED` как СООБЩЕНИЕ О НЕДОСТИЖИМОСТИ, а не как провал), и следующая движковая смена открывает этот журнал РАНЬШЕ акта. Акт `D39.206` всё это время нёс верные числа — разошлись НОСИТЕЛИ, а не факт: класс «поправил читателя, оставил писателя» (`D39.202` п.1). ⛔ **ТРИ ВЕЩИ, КОТОРЫЕ ОРКЕСТРАТОРУ НАДО ЗНАТЬ ДЛЯ ЛЕНДИНГА:** 1. **Наружу едет НЕ то число, что назвал промт, и это согласовано.** §4(3) назвал `denied estimate` и следующей фразой запретил его класс («цены вызовов не выходят»). Едет **недостача** `committed+reserved+estimate−ceiling`, поле `shortfall_micro_usd` (строка 278 называла `next_step_micro_usd`). Две оговорки в доке поля: при непустом полёте это ВЕРХНЯЯ граница; для `day`-скоупа поле ОПУЩЕНО (дневной потолок суммирует все книги стора, движковые цифры — одной). 2. **Третье лечение пункта 1 («обрамление как ДАННЫХ») в ТЕКСТОВОЙ форме невыполнимо.** `lang/data/injection.txt` побайтно входит в `EmbeddedVersion()` → `cutTag` → **внутрь каждого `unit.id`**: добавление одной строки пере-чеканило бы id всех книг. Сделано структурно. 3. **`res.Volume` при денежном стопе НЕ прикладывается.** Семь счётчиков `VolumeStop` — план; денежный стоп оставляет допущенные-и-не-доделанные юниты посчитанными как `Delivered`, а `LeftFresh` заниженным на них, и при `Left()==0` прогон, вставший посреди книги, объявил бы «дошёл до конца». Восьмого бакета нет ⇒ у денежного стопа СВОЙ леджер `Finished.Money{units_resolved, units_deferred}` из тех же счётчиков, что и `progress`. ⚠ **ЧЕТВЁРТОЕ ДЛЯ ЛЕНДИНГА, и это вход в СТРОКУ 283, а не мой дефект: `structure: detected` сегодня CJK-ONLY.** Сопоставление заголовков в интейке идёт по `lang.DefaultCJKSection()` — КОНСТАНТА (章节節回 + класс CJK-числительных), не данные пары. ⇒ книга в любой другой письменности возвращает `none`, как бы явно её главы ни были размечены. Асимметрию пак НЕ вносит — движок уже читает данные пары для РЕНДЕРА заголовка (`configs/langpacks/*/heading.txt`), а РАЗРЕЗ остаётся захардкоженным, и строка **283** называет именно этот раскол работой. Что поле ДОБАВЛЯЕТ: у асимметрии появляется имя на проводе вместо того, чтобы прятаться в числе глав — не-CJK книга честно говорит `none`, и форма заказа (D39.196) не предложит ползунок в ГЛАВАХ против разреза, которого никто не делал. Классификация сама пар-агностична (спрашивает, какой ПУТЬ провёл границы) и скажет `detected` без правки Go в день, когда разрез научится читать пару. ⚠ Первую редакцию комментария и отчёта я написала как «пар-агностично по построению» — это было пере-утверждение, поймано собственным проходом и исправлено в обоих местах. **ПРАВКИ ЧУЖИХ ТЕСТОВ — объявление по D39.183 (все три вызваны сменой поведения, заказанной паком):** · `runevents_test.go` — пин «the ceiling event must carry the fact and no figures» СУЖЕН, не снят: белый список ключей (`halted|scope|shortfall_micro_usd`), запрет любого `$`, ПЛЮС новое утверждение — book-стоп обязан назвать недостачу, day-стоп обязан её не называть. ⚠ Фраза ратифицирована (D39.106 §2/ПТ-33) — ноту о сужении берёт на себя оркестратор. · `wavepanic_test.go`, `volumepanic_test.go` — оба ВИСЛИ (`panic: test timed out after 1m30s`): парковали падающий воркер на `<-ctx.Done()`, которую вызывал ПОТОЛОК. Потолок больше не отменяет — это заказ пака. Триггер заменён, утверждения не ослаблены. **ПРАВКА ВНЕ ЗАКАЗА, взятая по своему усмотрению:** течь резервации на ветке `json.Marshal(resp.Usage)` (`stagerun.go`) — возврат без release и без settle. Довод: денежный путь, и у него появился второй читатель — утёкшая резервация ЗАВЫШАЕТ публикуемую недостачу. Ветка практически недостижима, поэтому её посадка занесена аргументированным выжившим, а не находкой. ⚠ **ЧЕТВЁРТЫЙ КЛАСС ЛОЖНОЙ ЗЕЛЕНИ, найденный в этой смене (общий, не про мой пак):** `t.Fatalf` из ПОРОЖДЁННОЙ горутины — `runtime.Goexit` не на той горутине: утверждение теряется, прогон висит до таймаута ПАКЕТА. **Посадка, чей отказ выглядит как таймаут, неотличима от нагрузки и потому не является посадкой** — а `Makefile` зоны сам документирует разброс `internal/pipeline` 95 → 560 с под параллельными сессиями. Рядом с тремя известными: упавшая сборка, вырожденное утверждение, эквивалентная посадка. **ГОТОВЫЙ ТЕКСТ СТРОКИ БЭКЛОГА** (таблица — зона оркестратора, поэтому текст лежит здесь, а заводит его он; уже принят и заведён как строка **291**): > **Отказ РЕЗЕРВАЦИИ на ретрае не деградирует и не оставляет следа — юнит может заклинить навсегда, а > волна не может продолжиться без дыры.** `maxTokensForAttempt` удваивает бюджет на каждой регенерации > (`disposition.go:398`) ⇒ attempt 1 резервирует вдвое больше attempt 0. Отказ ретрая уходит наверх из > цикла попыток (`stagerun.go:164-167`) РАНЬШЕ `UpsertChunkStatus` (`stagerun.go:285`) ⇒ чекпойнт > attempt 0 есть (реплей за $0), строки `chunk_status` нет, читающие модели видят `pending`. Следствия > два: (1) если потолок покупки не вмещает attempt 1 — юнит не доделается НИКОГДА, каждый резюм реплеит > attempt 0 за $0 и умирает на attempt 1, прогон уходит exit 4 при полностью доставленных купленных > юнитах; (2) продолжить волну после отказа ретрая нельзя без дыры в непрерывном префиксе — то есть цена > глобальной защёлки (недодача юнитов, которые ВЛЕЗАЛИ; разброс резервов внутри волны замерен 2.976×, > разбор 04.09) не снимается различителем «свежий/ретрай». Два пути, ВЫБОР НЕ СДЕЛАН: (а) отказ ретрая > деградирует во флаг attempt 0 — смена D2.3, закрывает оба следствия; (б) минимальная покупка платформы > ≥ `step_max_usd` движка — закрывает только (1) и стоит продукту минимальной покупки ~5 глав | > бэкенд+платформа | скоро | выбор владельца между (а) и (б) + пин | бэкенд-сессия денежного стопа 05.09 **ГДЕ ПРОМТ НАПИСАН НЕ ТАК** (требование §5-тер(а), полный список — §5 отчёта): §4(3) внутренне противоречив (см. выше) · §4(1) заказывает лечение, невыполнимое без нарушения §4(6) · §3 п.1 называет секцию `15-money-path.md`, переименованную 05.09 · §4(2) обосновывает защёлку доводом, который снят самой конструкцией (`haltErr` — отдельный слот, путь ошибки один при любом W); защёлка оставлена по ДРУГОМУ доводу — продуктовому · §4-тер риск (б) назван мягче, чем он есть: счётчики не «получают новую форму», а врут по шести полям из семи. ## Полигон **📌 02.09 · ПИНГ ОРКЕСТРАТОРУ (два входа в бэкенд) + ИТОГ СЛЕПОГО ЧТЕНИЯ. Решения владельца от 02.09 внутри.** Носители: пре-реги и результаты — `eval/dovodka/blind-read/` (`PREREG-BLIND-READ.md` + `RESULT-BLIND-READ.md` с семью эрратами, `PREREG-2-BLIND-READ.md` + `RESULT-2-BLIND-READ.md`), прибор дрейфа — `eval/dovodka/dreif.py`. * **РЕШЕНИЯ ВЛАДЕЛЬЦА 02.09 (ратификация за оркестратором).** (1) **Дефолт редактора — `low`**, бремя доказательства на том, кто включает дорогой режим. (2) Вопрос «`off` против `low` по качеству» **закрыт как неизмеримый этим прибором** — судейских реплик не покупать. (3) Питон-прибор дрейфа пишет полигон (сделано), **настоящий прибор — в движок, это пинг ниже**. (4) Покупка 50 глав на длину **отложена до прогона в бэкенде** (слово владельца). * **⚠ ВХОД 1 — офлайн-пересчёт по уже оплаченному тексту (`tmctl recheck` или равное).** Проверки движка исполняются ТОЛЬКО в момент генерации; готовый текст в базе перепроверить нечем, и потому частота ложных тревог пост-чека не измерима без покупки. Полигон закрыл дыру питон-двойником (`dreif.py`), но **это не тот же прибор**: у движка стеммер целевого языка и сохранённые формы, у двойника — сопоставление по началу слова. Два «детерминированных» прибора с разными ответами — тихий дрейф нормы; строку в бэклог просит полигон, решение за оркестратором. * **⚠ ПОПРАВКА К ЭТОМУ ПИНГУ (02.09, позже в тот же день): входов НЕ ДВА, А ЧЕТЫРЕ, и «включить гейт» из них самый мелкий.** Разбор начат вопросом владельца («в бэкенде нет майнинга term — „мастер гу“ не замайнится»). Проверено исполнением: **майнинг term РАБОТАЕТ** (68 записей класса `term`, `蛊师 → гу-мастер` в банке есть), но владелец прав по сути — цепочка «намайнил → классифицировал → подписал → инжектнул как закон → проверил» рвётся в ЧЕТЫРЁХ местах, и замеренный дрейф (30 ключей из 102 несут >1 передачу, максимум 7 форм) — их следствие. * **(1) `term` — класс-умолчание, а не решение.** `backend/internal/pipeline/banknote.go:79` дословно: «bankTypeOK is the accepted type set; **anything else falls back to "term" (a benign default)**». Две трети банка пробы (68 из 102) сидят в этом умолчании. * **(2) Классификатор умеет различать `term`, но в пробе НЕ ДОБЕЖАЛ.** Определение в `backend/prompts/zh-ru/classifier.md:20-23` точное («реалия, понятие, предмет, материал, вещество, класс существ — всё, что переводится ПО СМЫСЛУ», пример `元石 term`). Однако лог пробы: `batches_planned=8 · batches_running=6 · classify_batches_dropped=4` при `budget_usd=0.05` против `estimate_usd=0.0978`; итог `unanswered=7`, `reclassified=5`. Движок сам предупредил: «this bank is PARTIALLY consolidated — a budget cut a pass, so some terms were never offered to the role at all». ⇒ типы выставила банкнота или умолчание кода, а не тот механизм, который умеет. * **(3) Промпт банкноты недоспецифицирует класс `term`.** `backend/prompts/zh-ru/translator-banknote.md`: просит «новых имён собственных и терминов», список типов даёт, но **определения `term` нет, а единственный пример — `师父 наставник title`**, то есть образец уводит в титулы; лимит «не более 20 строк» на фрагмент вытесняет понятия в пользу имён (имена заметнее). Правка промта — не Go и пары не касается. * **(4) Инжект фильтрует по ПОДПИСИ, а не по классу.** `backend/internal/membank/memory.go:663`: `status == "approved"` → `Confirmed`, иначе `Ambiguous`; `priorityRank` (там же, ниже) вытесняет неподписанное первым при token-бюджете (`glossary_token_budget: 800` на 102 записи). При `approved=0` весь банк едет «неуверенным кандидатом» — форма не объявлена законом, и удерживать её нечему. Это и есть механизм дрейфа `蛊师` («гу-мастер» / «мастер гу») и `元石` (семь форм). * **⚠ (5) НАБЛЮДАЕМОСТИ НЕТ на редакторской стадии.** `retrieval_state` в базах пробы держит **35 строк, все под DRAFT-снапшотом** (`8d5721f65596`), под edit-снапшотом (`b76ab168d95b`) — **НОЛЬ строк**. Доехал ли банк до редактора и сколько записей вытеснено бюджетом, из артефактов узнать НЕЧЕМ. Все счётчики на черновой стадии нулевые закономерно: банк рождается ИЗ черновика, на нём его ещё нет. * **Порядок, который из этого следует** (предлагается, решение за оркестратором): наблюдаемость инжекта на edit-стадии → бюджет классификатора (пять центов режут половину работы) → определение и пример `term` в промте банкноты → подпись банка и заполнение форм → и только потом жёсткий режим гейтов. * **⚠ ТРИ ПОПРАВКИ К МОИМ ЖЕ УТВЕРЖДЕНИЯМ ВЫШЕ, найдены консилиумом 02.09 и пере-проверены мной исполнением.** · **(5) сформулирован неверно в ПРИЧИНЕ.** «Ноль строк под edit-снапшотом» — не разрыв, а схема: `PRIMARY KEY (book_id, chapter, chunk_idx)` **без snapshot_id** (`store/migrate.go`), редактор мержит в ту же строку, и `snapshot_id` в ней — просто последнее записанное. Вывод «наблюдаемости нет» ОСТАЁТСЯ верным, но дыра в другом: счётчики инжекта редакторской волны не пишутся никуда (`pipeline/chunkrun.go:202`). · **«ни один $0-гейт не поймал латиницу» — неточно.** Детектор латиницы ЕСТЬ и вызывается всегда (`checks/cheapgates.go:192`, `lintLatinResidue`), но по построению он **наблюдатель, а не вердикт**: дословно `cheapgates.go:22-27` — «They are OBSERVABILITY, never hard gates… never changes a chunk disposition». Гейт видел и молчал, потому что так устроен. · **Источник «cultivation» — НЕ glm-5.** Пере-проверено по стадиям: слово рождается в ЧЕРНОВИКЕ (`deepseek-v4-flash`, 7 клеток) во ВСЕХ руках, потому что черновик общий; редакторы DeepSeek его вычищают (**0** в финальных текстах `p9-low`/`p7-off`), а `glm-5` — нет (3 клетки на edit, **2 доживают до финала**). Значит это дефект не породителя, а фильтра, и прежняя формулировка «glm-5 опознаётся по латинице» верна по факту, но неверна по причине. * **Улика к строке 46, а НЕ находка: полный провал языка цели.** `books/dovodka/dv-i-z8-fb9ed5709e.json` — глава пары zh→**ru** переведена целиком **на английский**: пере-считано мной, **7104 латинских знака, 0 кириллицы**, `finish=stop`. ⚠ **Прежняя формулировка «главного, чего в пинге не было» СНЯТА 03.09: это уже заказанная работа.** Строка бэклога **46** называет ровно этот случай дословно — «Экран целевого языка: „полный связный перевод на английский" проходит»; дизайн пака **заморожен владельцем** (D39.92 п.1 closed-set + D39.93 изолированный модуль), предгейт — строка **113** (фикстура ~20 off-target). ⇒ ценность вычитки здесь — не гейт придумать, а **дать строке 46 живую улику с боевого прогона**. * **📌 03.09 · ВЫЧИТКА 17 ГЛАВ БОЕВОГО ПЕРЕВОДА ($0, 17 агентов Opus, по агенту на главу с исходником).** Материал — `p9-low` (дефолт редактора по решению владельца 02.09), экспорт `tmctl export --pairs`. Инструкция вычитчику разделяла ДВА уровня: «читатель споткнётся» (против них меряется планка владельца ≤2 на главу, D39.20) и «мелочь корректора». * **Планка НЕ взята: 59 блокирующих претензий на 17 глав = 3.5 на главу.** В планку уложилась 1 глава из 17. При этом все 17 вычитчиков независимо ответили «читается как книга» = ДА. * **Классы (всего / из них ловится детерминированно):** смысл-искажён 12/0 · имя-термин-непоследователен 10/10 · translationese-грубый 9/2 · род-гу 7/6 · логика-действия 6/1 · иное 5/3 · язык-не-тот 4/4 · пропуск 3/3 · меры 3/3. ⇒ **механизируемо 32 из 59 (54%) ПО ОЦЕНКЕ ВЫЧИТЧИКОВ**; ⚠ оценка завышена: прогон существующих `RunCheapGates` по 11 цитатам дал 1 срабатывание из 11 (сегодняшний код берёт заметно меньше). * **Остаток, который не берёт ни один детерминизм: 12 искажений смысла + 6 сломанных мизансцен = 1.1 на главу** — то есть НИЖЕ планки владельца. Образец (гл.1): «перекрыл им путь, **сделав шаг в сторону**» — по-русски «посторонился», фраза противоречит себе; в оригинале 横跨一步 = шагнул НАПЕРЕРЕЗ. * **⛔ Найдено проверкой самих вычитчиков (системнее, чем они доложили): заголовки глав теряются.** Исходник даёт `第二十六节:一切组织的本质` — номер И название; движок кладёт в заголовок только номер (`chunk/chunker.go` `stripHeading`/`ApplyHeading`), название сваливается в тело как обычная строка. Дальше как повезёт: **название уцелело у 11 глав из 17, потеряно у 6** ⇒ на 2283 главах это ~800 глав без названия вперемешку с озаглавленными. Ловится тривиально: заголовок состоит только из номера. Улика к строкам бэклога **160/161/162** и **201**. * Сырьё вычитки: `/tmp`-экспорт не сохранён (волатилен), воспроизводится командой `tmctl export --config arms/p9-low.book.yaml --pairs`; вердикты 17 агентов — в задаче воркфлоу `wfofkln2i`. * **📌 03.09 · КАНОН СУЩЕСТВУЕТ, ПОДПИСАН И НЕ ПОДАН В СТЕНД (проверено исполнением).** `~/books/gu-zhenren/guzhenren-seed-v2.yaml` — **58 записей, из них 53 `status: approved`**, 16 с полем `gender`. В нём ровно те термины, на которых спотыкались вычитчики: `资质 → талант` (канон владельца D39.21), `元石 → первобытный камень` (а в пробе намайнилось 7 форм), `甲等/乙等/丙等 → класс А/Б/В` (а в переводе «категория **C**» ЛАТИНИЦЕЙ), `蛊师 → гу-мастер`. **В `~/books/gu-zhenren/probe-4axes/book.yaml` ключа `glossary_seed` НЕТ — 0 вхождений**, и шапка стенда объявляет это сознательно: «Сид НЕ подключается — банк рождается майнером + банкнотой, как в холодном прогоне». ⇒ **Прежняя формулировка «банк не подписан» (запись 02.09) НЕТОЧНА и настоящим уточняется:** не подписан МАЙНЕНЫЙ банк, а подписанный канон просто НЕ ПОДКЛЮЧЁН. Весь измеренный дрейф (30 ключей из 102 с >1 передачей) — дрейф конвейера с отключённым каноном. Контр-факт на той же книге: с подписанным банком эффективная консистентность **99.3–100%** (Д50.2, 375–548 пар). ⚠ Записи `蛊` в сиде НЕ ХВАТАЕТ поля `gender` (средний род прописан прозой в `note`) и стоит `allow_short: false` при `minKeyLenHan=2` ⇒ односимвольный ключ структурно вне автомата. Это две строки ДАННЫХ, не код. * **📌 03.09 · СВЕРКА С ПЛАНОМ ПОСЛЕ ЗАМЕЧАНИЯ ВЛАДЕЛЬЦА — 10 «предложений» из 11 оказались уже заказанной работой.** Владелец: «вы рассуждаете без оглядки на ту архитектуру и код, что уже построена или ЗАПЛАНИРОВАНА». Замечание верное: консилиуму давали код и данные вычитки, но НЕ давали целевую архитектуру, ЕДИНЫЙ БЭКЛОГ и журнал решений. Тот же консилиум, подняв прежний контекст, прочитал план и снял свои же предложения. Сверено мной по носителям. * **Уже в плане:** вынести вердикт-поля из хеша = строка **49** (спека `backend/docs/D15.2-content-addressed-resume-spec.md`) · экран языка цели = строка **46** · заголовки глав = строки **160/161/162** и **201** (гейт пал словом владельца 15.08, D39.136 п.3) · петля ремонта = **построена** за `enabled:false`, включение — строка **13** (владелец) · морфо-гейт рода = строка **82** · числа и меры = строка **12** через триггер D39.79 п.4 · критик = строка **2** (владелец). * **Уже ПОСТРОЕНО:** род `neuter` end-to-end — **D39.69 §3** (`13-tech-debt-anchors.md`: «носитель ПОСТРОЕН»). Остаток по роду «гу» — **две строки ДАННЫХ** в сиде стенда (`guzhenren-seed-v2.yaml:291-300`: `allow_short: false`, поля `gender` нет) плюс ключ `glossary_seed`. * **⛔ Противоречит ратифицированному:** патч-протокол редактора ↔ **D39.108 п.1** «диффы откладываются» · критик как стадия движка ↔ **D38.4 п.2** «семантический span-судья — ОТКАЗ» · подпись ~30 ключей поимённо ↔ **D39.144** «подписывается ВЕСЬ банк ОДНИМ ОК; пер-термная масс-подпись = инерция» · канал идиом врезкой dst ↔ **D38.4 п.1** «глоссарий-сидинг чэнъюй НЕ делаем» · таблица мер ↔ **D39.79 п.4** «HARD-value-детектор НЕ строить». * **Что вычитка дала по-настоящему:** улики к уже открытым строкам — **46** (глава на английском), **82** (7 дефектов рода), **142/13** (классы для точечной починки), **160** (6 глав из 17 без названия ⇒ ~800 на книгу), **12** (триггер реопена по числам НАЖАТ: #46/#13/#11). Это подтверждение заказанного, а не новый список. * **Метод-урок, дороже находок:** сутки ушли на переоткрытие бэклога, потому что план не был подан консилиуму. **Любой панели, обсуждающей ЧТО СТРОИТЬ, план подаётся вместе с кодом** — иначе она уверенно переизобретает заказанное. ⚠ Для полигона отсюда следует и граница: строки 46/49/82/142/160/12 — **зона бэкенда**, полигон в них не лезет; его законная часть — улики и замер (см. ниже). * **⚠ ВХОД 2 — пост-чек банка не имел ВХОДА, а не только был выключен.** В пробе `gates.coverage.enabled: false` и блока `gates.glossary` нет — это известно; но сверх того: из 102 записей банка **ни одна не доведена до `approved`, и `decl` пуст у ВСЕХ**. Пост-чек проверяет подписанные термины (`membank/mempostcheck.go`), значит молчал он по двум причинам сразу. Условие включения жёсткого режима записано в самом коде — «после того, как владелец подтвердит точность», а точность мерить не на чем, пока банк не подписан. Порядок для бэкенда: подписать банк → заполнить формы → замер ложных тревог → решение владельца. * **ИТОГ СЛЕПОГО ЧТЕНИЯ (две редакции, 219 судей Opus, $0.66 на реплику `low₂`).** Редакция 1 дала 18:6 «дешёвая рука лучше» — **вывод СНЯТ**: судьям показывали усечённый черновик (стадия `edit` склеивает несколько draft-чанков; в 10 юнитах из 15 опора покрывала 55–79%). Редакция 2 на склеенном по манифесту черновике (покрытие 99–100%) плюс **активные нули** (`low₁` против `low₂`): **судьи назвали победителя в 29 голосах из 30 на чистом шуме**, перекос на шуме (80%) БОЛЬШЕ боевого (70%). Первичные исходы: точность 12:10:8 (p=0.842), художественность 19:8:3 (p=0.070, Холм **0.141**) ⇒ **различие НЕ ПРЕДЪЯВЛЕНО**. Механика вскрыта: в **73 голосах из 74** побеждал вариант с меньшим числом претензий, а счётчик упирался в потолок в половине голосов. Текстовый шум одной руки (0.799) больше межрежимного (0.820). * **ПРИБОР ДРЕЙФА, первые числа ($0, на уже купленном).** Терминов с более чем одной передачей в тексте — 13–16% от измеренных; сменивших форму между главами — 6–8%. Независимым путём (поле `spread`, считает сам движок): **30 записей из 102 несут >1 передачу, максимум 7 форм у одного ключа** (`元石`: «юаньши · камень юань · изначальный камень · первородный камень…»). ⚠ Разброс МЕЖДУ режимами (0.3–1.9%) **не превышает шум-пола** (2.4%, снят по паре реплик одной руки) ⇒ дрейф на этом отрезке — свойство черновика и банка, **не редактора**; экономия на редакторе к нему отношения не имеет. * **⚠ Мои ошибки этого пака, названные вслух:** первая редакция пре-рега имела невалидный первичный тест (ничьи в знаменателе против H₀=50% дают ошибку I рода 17.8%) и правило решения с непокрытым пространством исходов; гейт слепоты искал `[A-Za-z]{2,}` и пропускал одиночные латинские буквы (23–25 на руку, слепота при этом не пробита — асимметрия 8%); первый гейт покрытия мерил долю совпавших слов и срезал 14 юнитов из 15, потому что смешивал «нет опоры» с «сильно правил»; первый парсер банка искал `src:` вместо формата «ключ⇥передача» и печатал «дрейф 0%» на пустых вариантах — отказ пойман гейтом парсера, который теперь в приборе. Сверка с нормами оркестратора post-hoc: риг нарушил «оба порядка» (обе редакции), «полно-evidence окна» (редакция 1), «шум-полы измерены» (редакция 1), «детерминированный скорер > судьи» и D39.61 «вывод на агрегате до вскрытия единиц». **📌 02.09 · ПРОБА РЕДАКТОРА ПО ЧЕТЫРЁМ ОСЯМ КУПЛЕНА И ЗАКОНЧЕНА. Ответ на вопрос владельца «почему редактор дорог» получен: ОН ДУМАЕТ, А НЕ ПИШЕТ.** Отчёт — `docs/experiments/23-editor-tier.md` **Д54**. Пре-рег стенда — `eval/dovodka/prereg-4axes/PREREG.md` (фризы `c08b547` и `590256a`), журнал исполнения со всеми находками — `eval/dovodka/prereg-4axes/ISPOLNENIE.md`. Стенд — `~/books/gu-zhenren/probe-4axes/`. **Израсходовано $5.524817 из санкции $9.50; остаток $3.98 НЕ добирался.** * **E0 — ответ на вопрос.** Размышление = **77.9%** цены редактора без ручки (`p7-off`) и **76.6%** (`p9-off`); с `low` — 45.7% и 46.7%; у `glm-5` с выключенным thinking — **0.0%**. Ретраи: 39.3% и 26.3% цены руки против 1.8% и 6.0% у `low`. * **E1 (главный) — эффект ЕСТЬ.** Вилкоксон-Пратт, n=17, **p=7.6e-05**, Ходжес-Леман **×0.283**, ДИ **[0.175; 0.431]**. 19 пар из 40 цензурированы ⇒ величина — **нижняя граница**: `low` режет размышление **минимум втрое**. * **E2 — цена доставленного знака падает в 2.5 раза** (боевая ×0.407 [0.326; 0.605]). Все ЧЕТЫРЕ заранее объявленных варианта, включая строгое `delivered` и кэш-независимую цену, согласны по знаку и величине. * **E3 (ось промпта) — НИЖЕ РАЗРЕШЕНИЯ** (p=0.487). **E4 (взаимодействие) — ниже разрешения** (p=0.854), описательный по построению. * **E5 — опасение плана ОПРОВЕРГНУТО: `low` БЕЗОПАСНЕЕ.** Эхо-клеток у `∅` 2, у `low` **0**; обрывов по длине 10 и 9 против **1 и 1**. Критерий риска не предъявлен. ⚠ Эхо считается по СЫРОМУ ответу: санитайзер его вырезает, и по отгружаемому тексту эхо не видно вовсе. * ⛔ **ИЗ ЭТОГО НЕ СЛЕДУЕТ РЕКОМЕНДАЦИЯ СТАВИТЬ `low` В БОЙ.** Качество не судилось — прямо вне скоупа. Проба даёт цену рычага и снимает подозрение по эху; следующий шаг — судейство качества `low` против `∅`, и теперь его стоит купить. **⛔ ГЛАВНАЯ НАХОДКА О ДВИЖКЕ, КОТОРОЙ ПЛАН НЕ ЗНАЛ: АВТО-БАНК РАСТЁТ МЕЖДУ ПОКУПКАМИ.** Терминолог перезапускается в каждой руке и, пока у него есть бюджет, доращивает банк — а банк есть ВХОД РЕДАКТОРА. В базе `consolidated=51`, в первой же руке 81, `memory_version` уехал, edit-снапшот сдвинулся, движок потребовал `--resnapshot`. Без гарда это проявилось бы на втором юните уже с оплаченными клетками, а хуже — банк мог вырасти ПО-РАЗНОМУ в разных руках, дав редактору разный вход при внешне исправном кресте. Лечение: гонять базу конфигом БЕЗ стадии `edit` до неподвижной точки, где терминальное условие — **ноль свежих платных строк И ни одного отказа по деньгам** (одного «`memory_version` не изменился» НЕДОСТАТОЧНО). Стоило $0.0352. **⭐ И ещё три находки, полезные любому следующему замеру.** (1) **Проводная улика СУЩЕСТВУЕТ** вопреки §3 плана: `LOG_LLM_BODIES=1` + `LOG_LEVEL=debug` пишет сырое тело запроса (`obs/logging.go:72` ← `llm/httpllm.go:415`), только тела, без URL и заголовков — снято, что у `low`-рук в теле стоит `reasoning_effort:"low"`, у `∅`-рук ключа НЕТ, у `glm-5` — `thinking:{type:disabled}`. (2) **Ось креста можно доказать ЗА $0**: потолок «база + малая сумма» отказывает первой edit-резервации, но снапшот и джоб к этому моменту уже вычислены; ⚠ потолок обязан лежать НИЖЕ редакторской резервации, но ВЫШЕ батча терминолога, иначе ложная точка выглядит тишиной. (3) **`tmctl manifest` бесплатен и даёт `units_total` ДО покупки** — `n` пинится числом, а не «сколько получится» (здесь 17 глав → 20 юнитов, а не ожидавшиеся 24). **Самопроверка исполнением (мандат промта §7):** агент-контролёр на `fable` вёл всю сессию по распоряжению владельца и поймал у меня **шесть ошибок**, из них четыре — одного класса «показания собственного инструмента приняты за факт о мире»: слепой к эху E5, ковариата по первому чанку вместо суммы (15 юнитов из 20), ложная неподвижная точка банка, дефект регулярки, выданный за находку о проводе. **Все пойманы ДО того, как повлияли на результат**; реестр с классами — Д54.5. Я, в свою очередь, опровергла исполнением одну его находку и одну свою. **⚠ ЧТО ПРЕДЪЯВЛЕНО, А НЕ СПРЯТАНО:** гард «зелень на пустоте» прошёл ВПРИТЫК — у `p7-off` пустых ровно 4/20 = 20% при правиле «>20% ⇒ отказ», а по строгому определению доставки было бы 25% и прибор отказал бы; четыре оплаченных `decode_error` в `p7-off` на $0.689 (34.5% цены руки), все на ретраях после обрыва, при нуле в трёх других руках; три юнита выброшены из E1 по `R̂ ≤ 0`, и два из них — `low`-клетки с почти нулевым размышлением, то есть выброс делает вывод КОНСЕРВАТИВНЕЕ. Полный список — Д54.4. **📌 29.08 · ФАЗА Д — НА ОБА ГЛАВНЫХ ВОПРОСА ВЛАДЕЛЬЦА ОТВЕЧЕНО, ВОПРОС 0 ОСТАЁТСЯ ОТКРЫТЫМ. Сессия $0, ни одного платного вызова.** ⚠ **«Отвечено», а не «закрыто», и разница существенная:** на Вопрос 2 ответ дан в форме СЛАБЕЕ, чем звучит сам вопрос — минимакс не проверен (худший ВОЗМОЖНЫЙ жилец не искался), вендоро-независимость архитектуры НЕ проверена (буфер двухвендорен: черновик делает DeepSeek). Первая редакция этой шапки писала «ЗАКРЫТЫ», хотя буллеты под ней несли оговорки — поправлено адверсариальной приёмкой. Отчёт — `docs/experiments/23-editor-tier.md`, секции **Д35–Д38**. Агент-сессий 154 → **186 из 200**. Деньги не тронуты: резерв пака $1.2634 из $18.30 как был. * **Шаг 4 плана 22.08 ЗАКРЫТ** (Д36) — последнее незакрытое условие §7, которое можно было закрыть бесплатно. Дуэль «ролевой промт против его отсутствия» на 16 уже купленных карантинных клетках, панель из 5 армов с ГРУБЫМ ДЕКОЕМ (`ZD`), 16 читателей `fable-5`. **Промт различим: +1.50 места при пороге 1.13, знаковый p=0.0213, 13 глав из 16 в одну сторону** — ровно порог, объявленный пре-регом ДО чисел. ⇒ у прибора ЕСТЬ разрешение на промт-инженерном материале, и **всё, что фаза назвала неразличимым, меньше, чем ВЕСЬ ролевой промт**. * ⭐⭐ **И промт покупает ПРОЗУ, а не БРАК:** детерминированный счётчик дефект-классов разницы между «с промтом» и «без промта» НЕ находит (p=0.6875) при том, что грубый декой на той же панели ловит (p=0.0156). Класс Б: текст без промта читатель называет машинным в **9 главах из 16**, с промтом — **ни разу** (p=0.0039). ⇒ минимакс владельца получает третий член: по браку несут гейты, **по прозе — ростер И ПРОМТ**, и вес промта того же порядка, что вес целой дорогой стадии. * ⭐ **Закрыт долг Д34.5, который фаза назвала сама:** третий круг панели-0 тем же `fable-5` дал первую в фазе оценку СОБСТВЕННОГО шума прибора. **Доля чисто читательского шума в пороге = 0.34**; смена семейства стоит столько же (0.32–0.43) ⇒ подмена судьи по средним оправдана. ⛔ Но хвост разошёлся и **воспроизвёлся**: полный переворот порядка не случается внутри семейства ни на одной из 16 глав и случается между семействами на той единственной, где сталкиваются брак и проза — обеими межсемейными парами. Вердикт о буфере при этом устоял ТРЕТИЙ раз (p=0.0042 · 0.0213 · 0.0042). * **📌 ПИНГ ОРКЕСТРАТОРУ №19 — твой вопрос по Gemini (D39.164) ЗАКРЫТ, и без новых покупок.** Выживает **ПОСЛЕДНЕЕ** системное сообщение, выбрасывается ПЕРВОЕ: разность `RE.prompt_tokens − RQ.prompt_tokens` = **2436 РОВНО на всех 16 главах, sd=0**, а постоянного размера из двух системных только первое. Улика исполняемая — `eval/dovodka/sysmsg.py`, EXIT=0. Твои три поправки (переоценка «физически не может», повторяемость `Content.parts[]`, форум как не-источник) внесены в `00-provider-quirks.md` моей рукой, как ты и просил. ⛔ **И следствие для движка правится в ХУДШУЮ сторону, хотя дефект уже закрыт твоим же лендингом `7d0c6f2`:** до 28.08 хоп в Gemini терял **не глоссарий, а ВЕСЬ ПРОМТ СТАДИИ** — `render.go` кладёт промт первым, инъекцию второй. Любой исторический результат на Gemini-хопе до 28.08 читать как «стадия работала без своего промта». * ⛔ **СВЕРКА `--final` СДАНА КРАСНОЙ: ТРИ ПРОВАЛА, И НИ ОДИН НЕ ПРО РАБОТУ** (диагноз на каждый — Д39.2; гейты я НЕ чинил под зелень). ⚠ Первая редакция этого пинга называла ДВА и недосчитывала R37 — поймано адверсариальной приёмкой исполнением. (1) Переезд обнулил mtime всего сырья — 335 клеток Ф2 имеют ОДИН mtime, поэтому `eval/tenant_panel/verify22.py` считает границу двойной оплаты как `$0.000000` и роняет **R71**. Клетки времени покупки в себе не хранят ⇒ улика утрачена безвозвратно, результат — нет. (2) Улика **R77** («пинг в PROGRESS») ищет заголовок хроники за 15 августа со словами «ФАЗА Д», который вынесение хроники увезло в `docs/archive/PROGRESS-2026-08-10-15.md:73`=`сырьё снято, выводы ПОНИЖЕНЫ`. ⚠ Точную строку здесь НЕ цитирую намеренно: первая редакция этого пинга процитировала её — и гейт позеленел от того, что я НАПИСАЛ ПРО ГЕЙТ, а не от того, что исполнил обязательство. Это ровно та подмена, против которой реестр и заведён; поймано собственной сверкой `--final` ⇒ протух ГЕЙТ, а не обязательство. **Норма впредь: время покупки и время ответа писать ПОЛЕМ В АРТЕФАКТ, а не полагаться на файловую систему.** (3) **R37 — ложный КРАСНЫЙ от нотации, а не от переезда:** улика записана как `material_ja.py \| grep -q "СТОП\|OK "`, разборщик реестра восстанавливает `\|` в `|` ОБЕИМ чертам — и трубе оболочки, и альтернации внутри grep, — а без `-E` черта в grep литеральна. Сам замер зелёный: `[OK ] срабатываний нет: 0 из 48 чанков`, EXIT=0. ⚠ У этой же строки в прошлом был ложный ЗЕЛЁНЫЙ по той же причине — нотация ломает улику в обе стороны. **Реестр я не правил: чинить улики в момент сдачи — это и есть «дописать таблицу под результат».** ⚠ **И отдельная находка приёмки, НЕ моя:** в журнале агент-сессий есть доисторические дубли токенов внутри прогона `d4` (15 токенов заявлены дважды) — они стояли в HEAD до этой сессии, а `runs.py --selftest` такой класс не ловит. * ⚠ **Зона не запускалась на этой машине вовсе:** книги переехали в `<репозиторий>/books`, а риги ходят по `Path.home()/"books"` — **65 вхождений в 31 файле** (бэклог, строка 217). Поднято симлинком + пере-собран `eval/.venv` (CPython **3.14.7** против пина 3.14.4 — расхождение названо, риги `dovodka/` чистый stdlib). Оба шага записаны в `eval/README.md`; там же теперь карта зоны `dovodka/` — она описывалась ОДНИМ файлом при сорока скриптах. * ⭐⭐ **ДЕНЬГИ — свод на ОДНОМ прайсе и в главах Гу, которого у фазы не было (Д41).** Боевая связка «черновик `flash` → редактор `pro`» = **$127 за книгу в 1500 глав Гу, и 90% этих денег — РЕДАКТОР** ($114 из $127). **Редактор заменяем: тот же черновик с редактором `glm-5` = $20, в 6.3 раза дешевле, качество НЕРАЗЛИЧИМО** (3 круга чтения, 2 семейства, второй прибор). Однопроходка на той же дорогой модели — $62 (вдвое дешевле связки), на `gpt-5.6-luna` — **$7.6**, но в прод не идёт: цензур-ось не мерена, китайских клеток нет. ⚠ Сведено расхождение, лежавшее не разобранным: `research/04` давал книгу за **$7–15**, фаза — за $41–68. Оба верны — (а) «книга 1500 глав» в Д29.1 это 1500 НАШИХ единиц ≈ 735 глав Гу, (б) ресёрч считал ВИДИМЫЙ вывод, а у `deepseek-v4-pro` **46% токенов — размышление, и это ЧЕРНОВИК, а не проверка** (96% предложений финала дословно есть в трейсе): модель пишет перевод дважды и обе копии тарифицируются по выходу. **Правило для сметы: цену роли считать по `total_tokens`, а не по длине перевода.** * **ЧТО ОСТАЛОСЬ И СКОЛЬКО СТОИТ** (Д38.6, ранжировано): **Шаг 7 — 15 глав Гу ПОДРЯД боевым профилем с ЗАСЕЯННЫМИ характер-листами, ~$2 + движковый прогон.** Это единственный замер, дающий прибор под **Вопрос 0** («консистентность на всю книгу»), и он же готовая in-loop телеметрия прода. ⛔ Без засева характер-листов результат ложно-отрицателен ПО ПОСТРОЕНИЮ: полей пола в банке нет вовсе, механизма не существовало ни в одном прогоне. Дальше — цензур-ось дешёвой линии $0.2–0.6 · китайские клетки ~$0.3 · З-2 $0.35 (перед ним $0-долг К-3) · пере-покупка `ZP` ~$0.4. **В резерв $1.26 пункт 1 НЕ влезает — нужна новая фаза и слово владельца ДО начала. Потолки сессией не поднимались.** * **📌 ОРКЕСТРАТОРУ, мелочь чужой зоны:** строка бэклога **217** цитирует якорь `eval/conformance.py:48` с ожиданием `REPO = Path(...)`; я добавил в этот файл один импорт, и цель уехала на строку 49. Хук поймал, но правка — в таблице бэклога, то есть в твоей зоне: по правилу самого хука сообщаю, а не чиню. Сама строка 217 в силе и подтверждена этой сессией: **65 вхождений `Path.home()/"books"` в 31 файле**, лечение — одна разрешающая функция корня книг, а не симлинк. * ⛔⛔ **30.08, ПО ЗАМЕЧАНИЮ ВЛАДЕЛЬЦА ПРОЧИТАН ВЕСЬ КОРПУС ФАЗЫ — И ОН ПОПРАВИЛ МОЙ ЖЕ ОТВЕТ В ЧЕТЫРЁХ МЕСТАХ (Д42, Д43).** (1) **«$11 за книгу» — реальная таблица эксп-22, но по ИЮЛЬСКОМУ прайсу.** Пере-счёт тех же клеток по текущему: связка $40–43 вместо $13–14. (2) **Развилка владельца ПОТЕРЯНА всеми планами:** `PLAN-17-08.md:105-119`=`РЕШЕНИЕ ВЛАДЕЛЬЦА, КОТОРОЕ ЖДЁТ ЕГО САМОГО` — «черновая роль по НАШЕМУ ЖЕ правилу должна уйти с DeepSeek», luna $0.00357 против flash $0.00544. Ни в 21.08, ни в консилиуме, ни в 22.08, ни в моих Д38/Д41 этого пункта нет. ⚠ Приз развилки — **6%**, а не разы: редактор съедает 85% связки, и строка плана «$40 против $23» смешивала смену ЧЕРНОВИКА со сменой РЕДАКТОРА. (3) **«Однопроходка дешевле связки» снято прибором, который читает ОДНУ главу** — а по находке владельца (журнал §11) без черновика терминологу не из чего собирать банк, и «на одной главе банк не нужен, на книге в 1500 глав имена разъедутся». Кандидат `K7` (однопроходка → майнинг банка из её выхода → фиксер) не мерен ни разу. (4) **Конфликт приборов по замене редактора напечатан:** Д41 даёт `glm-5` неразличимым от `dspro` по слепому чтению, а счёт ошибок эксп-22 даёт `R2` против `R0` **−2.12, Холм 0.0188 — значимо хуже** на zh. Кто прав — вопрос приёмке. * ⛔⛔ **30.08, ЖИВАЯ ВАХТА D39.92 ПЕРЕ-СНЯТА — ВЕНДОР-СТРАНИЦА DeepSeek ИЗМЕНИЛАСЬ, И ЭТО БЬЁТ ПО ВСЕЙ АРИФМЕТИКЕ РАЗМЫШЛЕНИЯ (Д44).** `curl` HTTP 200, `guides/thinking_mode`, 108 336 байт, sha256 `f28c4324…`. Было (наша запись 10.08): две колонки, у `deepseek-v4-pro` **`low` маппится в `high`**, «рычаг бюджета размышления существует ТОЛЬКО у flash». Стало дословно: *«identical for `deepseek-v4-flash` and `deepseek-v4-pro`»*, таблица одна, **`low → low`**; тумблер `{"thinking":{"type":"disabled"}}` подан как общий. ⇒ **у якоря письма ПОЯВИЛСЯ рабочий рычаг размышления, которого не было при всех покупках фазы.** ⚠ Это ДОКА, не поведенческая проба — по норме «слаг ≠ модель» перед деньгами нужна живая проба (единицы центов); сессия её НЕ делает без слова владельца. ⚠ Побочно с той же страницы, чего у нас не записано нигде: *«Thinking mode does not support the `temperature`… will have no effect»* ⇒ **наш `temperature: 0.3` на `deepseek-v4-pro` молча игнорируется.** ⚠ И: `effort:"low"` у DeepSeek **пере-вооружает эхо-мину** — рычаг есть, бесплатным не будет. * ⭐⭐ **ЧИСЛА ПО ЛУНЕ ПЕРЕ-СНЯТЫ ПОКЛЕТОЧНО ПО ЗАПРОСУ ВЛАДЕЛЬЦА (Д44.6), И ОНИ БОЛЬШЕ, ЧЕМ Я ПЕЧАТАЛ.** Однопроходка, те же 16 английских глав, тот же промт, `finish=stop` 16/16 у обоих: `RN` (`deepseek-v4-pro`) медиана **$0.02011**/клетка, сумма $0.4938 · `RL` (`gpt-5.6-luna`) медиана **$0.00248**, сумма $0.0392 ⇒ **8.1× по медиане, 12.6× по сумме**, при качестве, которого прибор не разрешил. Вся разница — размышление: у якоря оно БИМОДАЛЬНО (466 … 19 559 токенов на главу), у луны прибито к ~1 000 явным `low`. ⛔ **НО ЭТО СРАВНЕНИЕ КОНФИГУРАЦИЙ, А НЕ МОДЕЛЕЙ, и ни одна прежняя строка этого не говорила:** якорю ручку не слали вовсе (= `high`), испытуемому слали `low`. По собственной норме фазы (Д28) это РАЗНЫЕ армы. ⇒ **Замер, который это разводит, стал возможен ровно сегодня** (см. пункт выше): те же 16 глав, тот же промт, `deepseek-v4-pro` с `reasoning_effort:"low"`, смета **$0.05–0.10**. Либо снимает с луны восьмикратное преимущество, либо подтверждает его при уравненных ступенях. **Самая дешёвая и самая информативная покупка, какую фаза может назвать; ждёт слова владельца.** * ⛔⛔ **ТРЕТЬЯ ТИХАЯ ПОЛОМКА ОТ ПЕРЕЕЗДА МАШИНЫ, найдена исполнением 30.08: в `eval/.env` у ВСЕХ СЕМИ ключей пропали подчёркивания** — `DEEPSEEKAPIKEY` вместо `DEEPSEEK_API_KEY` (и так же GEMINI/OPENAI/XAI/ZAI/KIMI/MISTRAL). Код читает `os.environ["DEEPSEEK_API_KEY"]` (`eval/tenant_panel/roster.py:41`=`DEEPSEEK_API_KEY`), `load_dotenv` отрабатывает, имени нет ⇒ **любая покупка полигона падает `KeyError`**. ⚠ Значения ключей не читались — снят только список ИМЁН и признак непустоты. **Файл владельца не тронут, обёртка-переименовалка не написана** (это запрещённый молчаливый обход). Чинится одной правкой на стороне владельца. ⇒ **Класс назван: переезд ломает окружение МОЛЧА, и каждая поломка вскрывается только исполнением** — до этого были пути `~/books` (65 вхождений в 31 файле) и обнулённые mtime (Д35.2). **Санкционированная владельцем покупка (Д45) стоит готовой и ждёт ровно этого: пре-рег заморожен, арм заведён, провод прочитан, промт сверен побайтно, смета $0.16 при свободных $0.285.** * ⛔ **РЕЕСТР ПОТЕРЯННОГО (Д43) — прямой ответ на «не хотелось бы расти по энтропии».** При каждой смене носителя курса часть намерений не переезжала, и никто этого не печатал. Собрано ~25 позиций: семь развилок на владельце · десять объявленных $0-замеров, которые не сделаны · **три долга ЧУЖИМ зонам, где полигон обещал пинг и не пингнул** · шесть выпавших из очереди покупок. **📌 Первое, что прошу оркестратора взять:** ⛔ **экстрактор epub сносит границы абзацев** (`HANDOFF-21-08.md:152`, консилиум поднял до ⭐ «починка ДО любого нового en-замера»): пинг обещан 21.08 и **так и не сделан**, а весь английский материал фазы снят с испорченной подачей. Плюс: английский пар-пакет не заленджен в `backend/prompts/`. **Норма, которую предлагаю завести: новый носитель курса обязан явно перечислить, что из старого НЕ переехало и почему.** * ⚠ **Незакрываемое панелями, названо прямо:** абсолютная база класса Б (Шаг 5.1). Читателя просят назвать худших ВНУТРИ панели — метка сравнительная, норма абсолютная. До отдельной абсолютной рубрики или человека норму «≤1 машинная глава на 25 глав Гу» печатать нельзя. * ⭐⛔ **30.08, ПОСЛЕ КОМПАКТА: КЛЮЧИ ПОЧИНЕНЫ ВЛАДЕЛЬЦЕМ, ПРОБНАЯ КЛЕТКА КУПЛЕНА ($0.038276) — И ГЛАВНОЕ ОНА ОТДАЛА БЕСПЛАТНО (Д45.5, Д46).** Несущая улика — не размер размышления, а **входные токены**: при побайтно одинаковых `messages` (sha256 сверен исполнением) вызов без параметра дал `prompt_tokens` **3270**, вызов с `reasoning_effort:"low"` — **3191**, то есть **−79**. **Два контроля детерминизма:** замер 05.08 (дефолт и `low` вернули ОДИНАКОВЫЕ 2124) и пред-полётные пробы самого рига (`84 · 84 · 84 · 84` на одном тривиальном запросе, четвёртая куплена 30.08 — то есть **дефолтный счёт входа не сдвинулся через смену вендорского сервинга**). ⇒ **параметр `low` на `deepseek-v4-pro` ТЕПЕРЬ ДОХОДИТ ДО МОДЕЛИ**, статус квирк-бюллетеня «НЕ УСТАНОВЛЕНО» закрыт в части «доходит ли» (новая запись **3г**). ⛔ **ВЕЛИЧИНА среза — НЕТ, и это находка против моего же пре-рега:** `RN` куплен 21.08, `RNL` — 30.08, а между блоками лежит **документированная смена вендорского сервинга** (её же зафиксировала вахта Д44) — сравнение приписывает ручке всё, что вендор поменял за девять дней; дрейф из §3б — второй конфаунд и слабее (у него есть знак, и он работает против нуля). Раздел Д45.3 «чего замер не закроет» не назвал НИ ОДНОГО — **дефект найден пере-чтением ПОСЛЕ фриза `87dd124`, печатаю против себя**. ⇒ ⭐ **Лечение одно: оба арма в ОДНОМ блоке вперемежку — и такой замер КУПИТЬ МОЖНО, вчетверо дешевле замороженного:** дизайн Д (интерливинг `RN2` против `RNL` на восьми дешёвых главах) стоит **$0.078–0.133** при свободных $0.2472, n=8 пар, минимальный двусторонний p = 0.0078; гард кассы его пропускает (проверено по коду, гард не тронут). **Пре-регистрация — Д47, заморожена коммитом, ⛔ НЕ КУПЛЕНО: санкция владельца была на ДРУГОЙ дизайн, переносить её я не вправе.** Рекомендация: пятнадцать клеток по фризу Д45 (дизайн А) **не покупать ни при каком ответе**; Д47 — по его слову. ⚠ **Первая редакция Д46 утверждала обратное — «ни один неконфаундированный дизайн не влезает» — и это было НЕВЕРНО** (пропущена дешёвая восьмёрка, при том что бимодальность нашла та же секция); сломал адверсариальный проход, разбор и цена ошибки — **Д46.6**, там же единственная находка прохода, которую я ОТКЛОНИЛ (корреляция по порядку вызовов: у всех 16 клеток `RN` один mtime, порядка не существует). Боевая ступень редактора **не тронута** (`eval/tenant_panel/roster.py` — правлен только комментарий, который до сегодня объяснял выбор снятой посылкой; гейт пака пере-снят, расхождение то же единственное mtime-шное). * ⭐⭐ **30.08, Д47 ЗАПУЩЕН ПО САНКЦИИ ВЛАДЕЛЬЦА И ОСТАНОВЛЕН ГАРДОМ ПОСЛЕ ПЕРВОЙ ПАРЫ — А КУПЛЕННОЕ ОКАЗАЛОСЬ ЦЕННЕЕ ЭНДПОЙНТА (Д47.6).** Списано **$0.134804**, ФД-N 3.187585 из 3.30, потолок НЕ поднимался. **Побайтно один промт, одна глава `b065a92dc0`, `reasoning_effort` не слался НИ РАЗУ: 21.08 модель думала 466 токенов, 30.08 — 17 757. ×38.** ⚠⚠ **ПОПРАВЛЕНО В ТОТ ЖЕ ДЕНЬ ПО ВОПРОСУ ВЛАДЕЛЬЦА (Д47.7): подавать ×38 как ЗАМЕРЕННЫЙ СДВИГ ВО ВРЕМЕНИ было нельзя** — это разность двух ОДИНОЧНЫХ розыгрышей у модели с большим разбросом. По лучшей имеющейся оценке (sd логарифма 0.82 ⇒ одно sd = ×2.3, шесть групп «тот же тег, разные розыгрыши», 18 вызовов, судейская роль) ×38 — это ≈3.1 sd: **редко, но возможно ⇒ причина НЕ УСТАНОВЛЕНА**, обе гипотезы живы, а чистых повторов одного промта на роли `onepass` в корпусе НЕТ ни одного. ⛔ **И первый заход к этой оценке был бы десятой ошибкой дня:** я сгруппировал вызовы по «модель·глава·роль», получил 100 групп и «разброс ×11» — а группы смешивают армы `RN`/`RC`/`RB` с РАЗНЫМИ промтами (на `27cb3a7e69`: 7 061 · 498 · 18 043), то есть мерили разницу инструкций, а не розыгрыша. ⇒ **Устояло то, что важнее причины: сравнивать одиночные розыгрыши нельзя ни при какой гипотезе — это осуждает и дизайн А, и МОЙ дизайн Д.** ⭐ Побочно Клейм 1 подтверждён на БОЕВОМ промте: `prompt_tokens` = **3256 и 21.08, и 30.08** (через девять дней и смену сервинга), а `low` двигает их ровно на **−79**; гейт провенанса пройден (Δpt=79, кириллица 1.000, латиница 0). **Эндпойнт по правилу: внутри блока ручка дала ×1.40** (меньше ×2.52, полученных через девять дней — конфаунд эффект РАЗДУВАЛ), годных пар 1 из 8, знаковый тест p=1.0 ⇒ ⛔ **«НЕ УСТАНОВЛЕНО»**, добор глав после чисел запрещён. Носитель — `eval/dovodka/stupen.py`, написан ДО прихода клеток, селфтест стережёт, что порог достижим только единогласием. ⛔ **Смета ошиблась на порядок, и это моя восьмая ошибка того же класса:** $0.078–0.133 объявлялись ценой ВОСЬМИ пар, одна пара стоила $0.1348 — **я оценил опыт по той самой базе, нестабильность которой опыт и должен был показать**. ⭐ **Цена ответов теперь СЧИТАЕТСЯ, а не угадывается (Д47.8):** при sd логарифма 0.82 парный дизайн ловит эффект ×2.5 за 13 пар (≈$1.1), ×2.0 за 22 (≈$1.8), ×1.4 за 93 (≈$7.6); отдельный дешёвый вопрос «модель сдвинулась или это кости» — четыре повтора без ручки на той же главе, **≈$0.31**. ⛔ **Но приоритет не здесь:** ручка даёт ×1.4–2.5, а рядом стоит рычаг ×7–11 — смена модели на `gpt-5.6-luna` (поглавно медиана ×7.1, по сумме ×11.4) — и он упирается НЕ в деньги, а в кап агент-сессий (нужно 16, свободно 14). Тратить доллары на ручку прежде, чем порядковый рычаг прочитан по КАЧЕСТВУ, — плохая экономика. ⚠ Операционное для чужих циклов: отказ гарда возвращает код 1, но в ФОНОВОМ shell `set -e` цикл не остановил — семь итераций вхолостую, $0. * ⭐⭐ **30.08, ПАНЕЛЬ `luna1` ПРОЧИТАНА ВСЛЕПУЮ ПО САНКЦИИ ВЛАДЕЛЬЦА («Да, давай подниму кап»), $0 (Д48).** Кап 200 → 215, израсходовано 201. Читались ЧЕТЫРЕ арма на 15 главах (16-я выпала: клетка `RN` не прошла гейт годности, пропуск напечатан): однопроходка на `deepseek-v4-pro` · **та же однопроходка на `gpt-5.6-luna`** · боевая связка · **её вторая генерация как собственный шум прибора**. ⛔ **Сначала поправка к моему же предложению:** развилка владельца от 17.08 — про ЧЕРНОВУЮ роль, а её приз пере-считан в Д42.1 как **6%, а не разы** (редактор съедает 85% связки) ⇒ читать «луну как черновик» значило бы потратить кап на шестипроцентный рычаг; читался порядковый (×7–11). **Результат: средние места `Z0` 2.33 · `ZF` 2.33 · `RN` 2.53 · `RL` 2.80; близнецы расходятся на +0.00 при пороге 1.06 (прибор без смещения), якорь↔`RN` +0.20 при пороге 1.30 (p=0.79), якорь↔`RL` +0.47 при пороге 1.26 (p=0.58), очно `RL` против `Z0` — 6:9.** ⇒ ⭐ **дешёвая луна НЕ ОТЛИЧИМА по качеству ни от дорогого дипсика, ни от связки.** ⚠ Но: разрешение прибора грубое — два прогона ОДНОГО конвейера расходятся на **1.33 места из 4**, то есть разрыв луны это треть собственного шума; направление, хоть и незначимое, **против** луны; панель не трогает банк/консистентность на всю книгу, цензур-ось жанра и перенос на zh. ⛔ **Это ПЕРВЫЙ круг, вердикта ещё нет — правило конъюнкции требует повтора.** Дисциплина: ключ закоммичен ДО ответов, обёртка — замороженный `15cfac60`, модель читателей сверена ИСПОЛНЕНИЕМ (во всех 15 транскриптах `claude-fable-5`). ⛔ **Второй круг упирался в ОДНУ сессию — моя арифметическая ошибка при подъёме капа** (осталось 14, нужно 15); резать панель до 14 глав решением сессии запрещено. ⭐⭐ **ВТОРОЙ КРУГ ПРОЙДЕН (кап 215 → 220 по слову владельца, Д48.5): вывод ПОВТОРИЛСЯ, конъюнкция закрыта.** Средние места круг 1 → круг 2: `Z0` 2.33 → 2.20 · `ZF` 2.33 → 2.53 · `RN` 2.53 → 2.60 · `RL` **2.80 → 2.67**; якорь↔`RL` +0.47 (порог 1.26, p=0.58) → **+0.30** (порог 1.11, p=0.77), то есть отставание луны во втором круге даже СОКРАТИЛОСЬ. Круги разведены по норме рига (ответы первого унесены в `krug1/`, второй писал по ТЕМ ЖЕ пакетам; свод первого из подкаталога воспроизвёл прежние числа до сотой); модель всех 30 читателей сверена по транскриптам. ⚠ Регистратор отработал как сторож: пере-заявить те же главы отказался, пока сессии первого круга не закрыты (`ГОНКА СЕССИЙ`). ⇒ **однопроходка на `gpt-5.6-luna` неотличима по качеству от однопроходки на `deepseek-v4-pro` и от боевой связки на 30 слепых чтениях**, при цене ниже — ⚠ **но число «7.1× по медиане» я подавал НЕВЕРНО, поправка в Д48.6 по вопросу владельца.** (1) В знаменатель попала ПУСТАЯ клетка дипсика (`100b088f71`, ноль знаков, та самая, что не прошла гейт годности): на 15 годных пар медиана **10.5×**, по сумме **12.0×**; побочно — непригодную клетку выдал дипсик, 1 из 16, у луны 0 из 16. (2) Тяжелее: **медиану тут вообще нельзя приводить — распределение ДВУГОРБОЕ** (восемь глав ≈2×, восемь ≈20×, посередине пусто), и она скачет 7.1 → 10.5 от выброса одной клетки. Честно: **от 1.3× до 34×, и величина следует за тем, сколько дипсик надумал**. (3) **Разложение:** 87% цены дипсика — размышление (разброс по главам ×42: 466–19 559), у луны 49% и ×3 (511–1 535); **контрфакт «дипсик думает как луна» даёт всего ×2.9** — это чистый прайс и накладные, остальное объём размышления. (4) ⚠ Конфаунд в силе: дипсик ехал без ручки (дефолт `high`), луна на явном `low`; ручка стоит ×1.40 (Д47.6) — сузит, но не закроет. (5) ⚠ Воспроизводимость самой луны **не мерена ни разу** (0 групп повторов на 749 вызовов), а её `reasoning_tokens` подозрительно кратны 512 — возможен блочный учёт, проверить до смет. ⛔ Переключение — решение владельца, и перед ним стоит незакрытый гейт, названный им самим 16.08: у однопроходки нет черновика, из которого терминолог добывает свидетельства для банка (Д42.3). * ⛔ **30.08, ЖИВАЯ СВЕРКА ПРАЙСА GEMINI ПО ВОПРОСУ ВЛАДЕЛЬЦА — ОДИН ПИН ВДВОЕ ЗАВЫШЕН** (квирк-бюллетень, раздел прайса; источник `ai.google.dev/gemini-api/docs/pricing`). `gemini-3.1-flash-lite` — пин верен ($0.25/$0.025/$1.50). ⛔ **`gemini-3.6-flash`: у нас $1.50/$0.15/$7.50, у вендора дословно «$0.75 through December 31, 2026», то есть выход сегодня $3.75 — наш пин это ПОСЛЕ-промо цена, сметы на этой модели завышены ×2.** ⚠ **Пин я НЕ правил сознательно:** `roster.cost()` считает клетки ИЗ ПИНА, и правка переписала бы стоимость **8 уже купленных клеток** (Д32.11 — леджер есть оценка) ⇒ решение за владельцем. `gemini-3.1-pro-preview` верен для ≤200k, но у вендора есть не записанный у нас тир >200k ($4/$0.40/$18). ⭐ **И на странице есть `gemini-2.5-flash-lite` — $0.10/$0.01/$0.40 выход, втрое дешевле самой дешёвой нашей модели**; в смету брать НЕЛЬЗЯ: 2.5-серия имеет shutdown 16.10.2026 и интермиттентный 404 при живом слаге, качество и эхо не мерены. **Урок для всех пинов: промо-цена с датой окончания попадает в ростер как постоянная и тихо врёт — у пина обязана быть дата и оговорка о промо.** **📌 ПИНГ ПОЛИГОНУ от оркестратора №19 (28.08, D39.164) — вендор-вердикт по Gemini для `docs/experiments/00-provider-quirks.md`.** Материал добыт бэкенд-сессией (curl по вендор-доке, не пересказ), но файл — ВАША зона, вписываете вы. ⚠ Вендор-основание ДОСЛОВНО, со ссылкой и датами снятия, уже лежит в `backend/configs/models.yaml` у провайдера `gemini` (греп `ВЕНДОР-ОСНОВАНИЕ`) — сюда не переписываю. **Строка 157 квирков несёт ТРИ утверждения сильнее источника:** (1) «слой ФИЗИЧЕСКИ не может пронести больше одного системного» — вендор говорит про НАТИВНЫЙ `systemInstruction`, а что делает с двумя системными OpenAI-совместимый ШИМ, не документирует нигде; (2) «уход на нативный API проблемы не решает» — верно по сути, не по причине: `Content.parts[]` ПОВТОРЯЕМОЕ, и нативный API МОЖЕТ нести N системных текстов как N частей ОДНОГО `Content`; (3) «форум Google» — НЕ вендорский источник: тред `discuss.ai.google.dev/t/86097` — два поста, оба от НЕ-сотрудников (staff=false), 30.05.2025, ответа Google нет, а читается наравне с нашим замером. **Открыто честно:** «выживает ровно одно» против «не выживает ни одного» не разрешено — маркер пробы приписан к `msgs[0]`, и его отсутствие совместимо с обоими чтениями, а зеро-системного контроля в скрипте нет. Твёрдо: НЕ склеиваются (`prompt_tokens` 2994 → 535) и first-wins ложно. **Дешёвое решающее доизмерение:** тот же скрипт, маркер на ПОСЛЕДНЕЕ системное плюс user-only базовая клетка. ⚠ Граница: проба гонялась на `gemini-3.1-flash-lite`, а в цепочке эскалации стоит `gemini-3.1-pro-preview` — слой тот же, слаг другой. Для движка безразлично: склейка на нашей стороне заленджена (D39.164). **ИТОГ ПОЛИГОН-СЕССИИ 23.08 — ШАГ 1 ПЛАНА 22.08 ЗАКРЫТ (панель-0, $0).** Отчёт целиком — секция **Д32** `docs/experiments/23-editor-tier.md`; фризы `bedc39a`, `9e33a1b`; денег не потрачено (панель собрана на уже купленных клетках). **Вердикт (интеракция «архитектура × жилец на ИСПЫТАННЫХ жильцах», не минимакс):** слабый жилец `glm-5` РЕДАКТОРОМ над боевым черновиком неотличим от боевого `deepseek-v4-pro` в той же роли (разрыв средних мест **+0.00**, p=0.80), а ОДНОПРОХОДКОЙ различимо хуже (**+1.12** места при пороге 0.99, знаковый **p=0.0042**, +13 фаталов p=0.0312) ⇒ **буфер архитектуры существует и замерен** — ⚠ на 16 главах. **⛔ ДЛЯ БЭКЕНДА:** в **2 окнах из 8** с первым лицом пол рассказчика по главе НЕ УСТАНАВЛИВАЕТСЯ вовсе (эталон снят вслепую тремя независимыми чтениями на главу), а полей пола в банке НЕТ (`~/books/role-topology/bank-en.json`, 25 терминов) ⇒ закрыть эти ~25% может ТОЛЬКО книжная память; смыкается со строкой бэклога **210**. **⚠ ОТКРЫТО НА ВЛАДЕЛЬЦЕ:** сверить **$17.04** с реальным счётом DeepSeek может только он. Долг В21 (сверка кассы двумя путями) ИСПОЛНЕН, результат отрицательный: сверка на диске НЕВОЗМОЖНА в принципе — `cost_usd` вычисляется нашим же `roster.cost` (`buy.py:93-95`), а не приходит от вендора; на 213 клетках у четырёх вендоров из шести арифметика сходится до последнего знака, а «офф-пик = ½» в ЗАПИСАННЫХ ценах НЕ наблюдается. **⚠ Пинг оркестратора №18 — 20.08 (протухшие цены в квирках, чинить вашей рукой).** `docs/experiments/00-provider-quirks.md` до сих пор утверждает, что цены после катовера НЕ изменились («flash $0.14/$0.28»). Это опровергнуто пере-пином 13–15.08 (D39.137): таблица запинена ПИКОМ — flash 0.44/1.32 при кэш-хите **0.014**, pro 1.32/3.96 при кэш-хите **0.044** за 1M (сверено с `backend/configs/models.yaml:182,198`=`cached_per_m` и телом D39.137 §2а), и счёт шиппинга = 100% DeepSeek ⇒ ×4.2–4.4 в пике. Квирки — ваша зона, рукой не трогаю; поправьте при ближайшем касании, потому что по ним считают деньги проб. ⚠ **ВТОРОЙ пункт этого пинга СНЯТ 05.09 как ЛОЖНОЕ ОТРИЦАНИЕ оркестратора.** Он утверждал, что факт про пиковые окна цен «в квирках ОТСУТСТВУЕТ (греп = 0)». Факт ТАМ ЕСТЬ (`docs/experiments/00-provider-quirks.md`, греп `ПИК DEEPSEEK`) — и несёт поправку, которой не было в моей копии: **пик только ПО БУДНЯМ, выходные целиком идут по офф-пику**. То есть оркестратор, живший по своей копии, отодвигал платное на вдвое дороже по выходным. Копия снята, единственный носитель — квирки. Отрицание было получено грепом, который не мог сработать; урок общий: **команда, на которой стоит отрицание, приводится в тексте, чтобы её мог воспроизвести другой.** ⚠ Третий пункт того же аудита (`eval/README.md` держит мёртвый СТОП на платные прогоны) сведён ниже, в пинг №20 — один носитель на факт. ⚠ **ВТОРОЙ пункт этого пинга ПЕРЕ-СНЯТ 05.09: спора нет и не было.** Он утверждал, что квирки и `docs/STACK.md` говорят «ручки эффорта у `deepseek-v4-pro` НЕТ» — оба говорят ОБРАТНОЕ (квирки §3г: «параметр `low` на `pro` ТЕПЕРЬ ДОХОДИТ ДО МОДЕЛИ», $0.038276, −79 prompt_tokens; `STACK.md:11` — то же). ⚠ Это был ЧЕТВЁРТЫЙ носитель фантомного противоречия, снесённого D39.200 п.4(а), и он пережил первую зачистку. Живой остаток один и он не спор: **вендор-сверка САМОГО МАППИНГА (`low` → что именно) и ВЕЛИЧИНА эффекта** — замера поведением после 13.08 нет ни у кого. Это боевой РЕДАКТОР и апекс эскалации. **Закрывается вендор-сверкой, а не выбором стороны** (гардрейл владельца) — и вы это только что делали по Gemini, то есть заход дешёвый. Носитель в трекере — строка **237**(б). **⛔ ПИНГ ОРКЕСТРАТОРА №20 ЗОНЕ — ТРИ ПРОТУХШИХ МЕСТА, все три ЖИВЫ на 02.09 (правки зонные, рукой не трогаю).** 1. **`eval/README.md` первой врезкой держит СТОП на платные прогоны** — «Платные прогоны/докупки СТОП до ре-пробы (бэклог-строка 74)». Строка 74 закрыта (D39.95), ограничение пало лендингом 112 (D39.97), `pipeline-c1.yaml` несёт `reasoning: "low"` с объяснением, а зона всё это время платно гоняет фазу Д: врезка объявляет запрещённым то, что делается ежедневно, и этим обесценивает все прочие ⚠ в файле. Живым из неё остаётся только ⚠0731 (смена весов под слагом) и стохастичность эха. ⚠ **Пункты 2 и 3 СНЯТЫ 05.09 — зона их закрыла, пинг об этом не знал.** (2) `eval/README.md:40` уже говорит «не один скрипт, а зона из ~40», а `docs/experiments/README.md` несёт строки и 22, и 23 (`:40`, `:41`). (3) `naklon.py` в `main` ВЛИТ: `git ls-tree -r HEAD --name-only -- eval/ | grep -c naklon` → 1, и в `eval/dovodka/` у HEAD 90 отслеженных файлов, а не 42. **Живым остаётся только пункт 1.** **ФАЗА Д «ДОВОДКА ЭКСП-22/23» — ИДЁТ.** ⚠ **Живое состояние фазы живёт В ЗОНЕ, не здесь** (`eval/dovodka/` — планы, консилиум, ревью; свежий носитель курса зона называет сама), приёмка фазы — у ПАРАЛЛЕЛЬНОГО оркестратора, деньги и цепь потолков — `eval/dovodka/money_d.py` (`PACK_CEILING`/`CEILINGS`), а не литералом здесь: три поколения записей в одном месте и были причиной, по которой состояние фазы стало нечитаемым. *(Хроника фазы Д — записи 10.08 (сессия №1) и 15.08 (сессия №2, сквозной аудит дуги 19→23 и пере-судейство `tier`) — вынесена в [archive/PROGRESS-2026-08-10-15.md](archive/PROGRESS-2026-08-10-15.md) с тремя поправками в шапке: потолок, закрытые пункты листа владельца, протухшие «долги». Открытым на владельце из неё остаётся ОДИН пункт — возражение Sol по проходу `tier`.)* **Диспозиция оркестратора №17 (15.08), живая до приёмки фазы Д:** просьба хендоффа «эррата zh-канона: пере-сборка = правка закрытой оси, ратифицирует оркестратор» (`docs/POLYGON_PHASE_D_HANDOFF.md`, греп `Пере-сборка = правка закрытой оси` — файл дирти, номер строки не ставим по норме D39.179 п.4; завышение +0.0039, вердикты не двигает) — **к ПАРАЛЛЕЛЬНОМУ оркестратору при приёмке, не к движковому** (приёмка фазы Д — его зона, №17 полигон не трогает **по слову владельца**). Прожитое из записи (вторая передача и мелочи аудита корпуса) — `archive/reports/CORPUS_AUDIT_2026-08-15.md`; санкции владельца по деньгам фазы и замене ja-книги — D39.136 п.1. *(Память · Голос и состояние · Ридер-IDE — ЗАКРЫТЫЕ секции (D39.125): темы исполнены/переехали в зонные журналы; хроника — в архив-слайсах. Фронт пишет ТОЛЬКО в frontend-PROGRESS.md.)*