# Бэкенд-пак: АНГЛИЙСКАЯ ПАРА en→ru — движок обязан ЗАПУСТИТЬСЯ и отдать книгу, которую можно читать > Выдача №15 очереди №23. Зона — `backend/`. Пак **$0 по умолчанию**; единственный платный шаг назван в > §4.10 и без моего слова не делается. > ⚠ **Числа и адреса этого промта сняты МНОЙ по дереву 17.09, каждое — названным прибором.** Те, на > которых ты строишь решение, пере-сними своим: заимствованное число улики не заменяет. > ⛔ **И честно о цене этого правила: первая редакция промта содержала ЧЕТЫРЕ моих ошибки**, все нашёл > опровергатель, и все — одного класса: **число снято не на той популяции**. Я мерил текст документа там, > где движок читает ГРУППУ документов; цитировал отозванную формулировку ряда, не прочитав его баннер; > обрезал строку ноты на 200 знаках и заключил, что тела нет. Ниже — исправленное. Считай это не > извинением, а описанием того, как именно здесь ошибаются. ## 1. Какая проблема и что решит твой результат Проект объявляет: движок один, пара — ДАННЫЕ, и ревью-вопрос по умолчанию — «заработает ли пара, которой в репо ещё нет, без правки Go?». На английском ответ сегодня — **нет, и даже не «плохо», а «не стартует»**. Замерено мной: - `backend/configs/pairs/en-ru.yaml` — **293 байта, 6 строк**: только `pair: en-ru` и коридор `len_ratio_bounds: [0.70, 1.4]`. ⭐ Его собственный комментарий уже называет обе стены: «своей калибровки нарезки нет, пакета промптов `prompts/en-ru/` нет (книга на этой паре упадёт громко на загрузке)». **Это не открытие пака — это пин в данных, написанный раньше нас.** - `backend/prompts/` — **один** пакет (`zh-ru`, 11 файлов). `backend/configs/langpacks/` — **три** (`ru`, `zh`, `zh-ru`). - Целевой слой (русский) привязан к **ЦЕЛИ**, а не к источнику ⇒ английская пара наследует слой 7, банк-инъекцию и читательские слова **бесплатно**. Работа лежит на осях ИСТОЧНИК и ПАРА. **Твой результат:** английская книга проходит от интейка до файла, который читает человек, а деньги, эхо и нарезка ведут себя на латинице так же честно, как на китайском. ⚠ **Три решения владельца (17.09) — исполняются, не обсуждаются:** книга — **«Империя рассвета»** (Кристофф, том 3 «Империи вампиров», `books/Kristoff_Jay_-_Empire_of_the_Vampire_3_-_Empire_of_the_Dawn.epub`, 18 634 457 байт, в дереве); размер среза меряется **по токенам** — равной работой и деньгами; **эксперимент двух переводов идёт ПОСЛЕ этого пака**, обе половины сразу. ## 2. Зона записи и git Пишешь `backend/` и свою секцию в `docs/PROGRESS.md`. **Не коммитишь** — дерево передаёшь мне. Чужие незакоммиченные файлы не трогаешь. **`.env` не читаешь никогда.** Запрещены `git add -A` / `git add .` / `git commit -a`, `reset --hard`, переписывание истории, `checkout` поверх грязного дерева. Книги и производные не коммитятся: `books/` — симлинк в отдельный репозиторий со своим origin. ⚠ **`books/` невидим двум приборам сразу, и оба дают ложный ноль:** обёртка `grep` чтит `.gitignore`, а `find` не спускается в симлинк без `-L`. Замер: `find books -type f` → **0**, `find -L books -type f` → **10534**. Бери `command grep` и `find -L`, и печатай знаменатель рядом с любым нулём. ⛔ **ВХОД ЗОНЫ.** Дерево передаётся тебе ПОСЛЕ лендинга предыдущего пака (`backend/` сейчас держит 31 незакоммиченный путь чужой банк-работы). Твоя первая команда — `make battery` на полученном дереве, и её результат ты **записываешь числом в записку-план как ВХОДНУЮ строку**. Красное на входе — пинг мне, а не починка: это не твой предмет. ## 3. Карта чтения — ЗАКОН, пять позиций 1. `CLAUDE.md` (корень) — канон, гардрейлы, роли зон. 2. `docs/architecture/09-target-architecture.md` §0.1 и §Цели — почему пара это ДАННЫЕ. 3. `docs/architecture/12-go-style-notes.md` §1 — норматив зоны. 4. `docs/experiments/00-provider-quirks.md` — провайдерские ловушки, ПЕРЕД правкой вызовов. 5. `docs/experiments/01-token-calibration.md` — калибровка: английский **3.64** знака без пробелов на токен, китайский **1.38**. **Код первичен:** адреса ниже — отправные точки, не истина. ## 4. Что построить ### 4.1. ОСТАНОВКА ПЕРВАЯ — до единой строки кода. ДЕЛАЙ РОВНО ТАК **Слово владельца:** «обязательно остановись на селф ревью и выдай сессии… фабла5 который верифицирует алгоритм исполнения и данных в бэкенде для английского + адверсариальное селф ревью и контроль исполнения». 1. **Инвентарь исполнением.** Пройди путь английской книги СВОИМИ прогонами и выпиши, где он встаёт. Отправные точки (все четыре проверены мной по содержимому цели): `backend/internal/config/pipeline.go:1063` · `backend/internal/pipeline/runner.go:364` · `backend/internal/lang/structure.go:158-161` · `backend/internal/pipeline/runner.go:432-439`. 2. **Прочитай, что УЖЕ померено живьём на этой самой книге** — ряд **315** бэклога закрыт замером 06.09: `tmctl manifest`, `EXIT 0`, $0, `structure: declared`, **71 глава / 351 юнит / 356 чанков**, нумерация плотная 1..71, `title_raw` на проводе 71 из 71, `heading` пуст у ВСЕХ глав. ⛔ Не открывай это заново. 3. **Подними советчика Fable 5 — ОДНОГО, с постоянным контекстом** (`model: "fable"` явно; канон: один фабл на сессию, вопросы ДОСЫЛАЮТСЯ тому же агенту, второго не поднимают). Предмет задай: «вот алгоритм исполнения английской пары и данные, которые я заведу; найди, где он ломается на латинице и где данные не выражают того, что обещают». Он **советчик, а не источник истины** — посылки проверяются деревом. ⚠ Обычные субагенты потолком не ограничены; их поднимать разрешаю явно. 4. **Только после этого** — записка-план (§7) и первая строка кода. ### 4.2. Стена 1 — промт-пакет пары. Это СОДЕРЖАНИЕ, и оно главное. РЕШИ САМА состав Загрузчик ищет промт по конвенции `/<пара>/<роль>.md` (`backend/internal/config/pipeline.go:545`); файла нет — `RefusalBadConfig`, `EXIT 10`. ⚠ **Стена НЕ абсолютна, и это уже использовано:** у пар-конфига есть ручка `prompts_root` (`backend/internal/config/pair.go:33`), и именно ею предыдущий пак прогнал ЭТУ книгу без каталога `prompts/en-ru/` в дереве (ряд 315). ⇒ **пакет строится не для того, чтобы обойти стену, а потому что он ПРОДУКТ** — прямой рычаг против translationese, цель №1 канона. ⛔⛔ **И ВОТ ГЛАВНОЕ В ЭТОМ ПАКЕ — СЛОВО ВЛАДЕЛЬЦА 17.09, ДОСЛОВНО:** «код может быть и да, но вот **данные надо написать**. Посмотреть на китайский и по аналогии, но при этом **уникально описать английский язык**. Это очень важно так как от этого **качество перевода зависит**. Именно поэтому я тебе и разрешал выдать фабла 5 другой сессии которая этот пак будет исполнять». ⇒ **Центр пака — не стены и не тихие дефекты, а СЛОЙ ДАННЫХ АНГЛИЙСКОГО ЯЗЫКА.** Китайский смотришь как образец ФОРМЫ — какие вопросы язык обязан о себе ответить, — и отвечаешь на них **про английский, его собственными категориями**. ⛔ Перенос китайских категорий на латиницу — это и есть та «копия без предмета», которая зеленеет и портит перевод молча. **Образец в числах (замер мой, непустые строки).** `configs/langpacks/zh/` — одиннадцать обязательных таблиц канала морфологии, и вот их наполнение: `title-suffix` 26 · `ordinal-title` 15 · `surnames-compound` 15 · `rank-word` 8, а `alias-particle` · `grade-prefix` · `numeral` · `sentence-terminator` · `surnames-single` · `title-formant` · `topo-suffix` — по **одной**. `configs/langpacks/zh-ru/` — четыре файла пары: `palladius` 87 · `dc-checkers` 42 · `palladius-phonotactics` 16 · `heading` 1. `configs/langpacks/ru/reader.txt` — 7 строк, и **его английская пара наследует даром**: целевой слой привязан к цели. ⭐ **Отсюда свобода, которую надо знать до начала:** загрузчик требует, чтобы объявленная таблица была **НЕПУСТОЙ**, а не полной (`backend/internal/lang/langpack.go:519-529`, каждая строка — `req(...)`). Семь китайских таблиц из одиннадцати удовлетворяют это одной строкой. ⇒ **английский вправе описать себя по-своему и коротко там, где ему нечего сказать, — но НЕ вправе соврать**, положив туда китайское. **Что английский обязан рассказать о себе, и чего в китайском нет вовсе** (это направление, а не список — состав решаешь ты и защищаешь аргументом): - **Регистр как сигнал имени.** В китайском регистра нет; в английском заглавная буква — главный носитель «это имя собственное», и нормализация ключа его СТИРАЕТ (§4.7). Что тогда несёт сигнал? - **Частицы и приставки фамилий** — `de` · `van` · `von` · `O'` · `Mc` · `Mac` · `Fitz`: где кончается частица и начинается имя, и как это едет в русский. - **Титулы и звания** — их у английского два слоя: препозитивные (`Sir`, `Lord`, `Captain`) и постпозитивные (`Jr.`, `Sr.`, `PhD`), и китайская таблица `title-suffix` описывает только второй род. - **Дефисные и многословные имена собственные**, которых китайская односложная морфология не знает. - **Топонимические форманты** — `-ton`, `-shire`, `-ville`, `-burg`: аналог `topo-suffix`, но с другой механикой границы слова. - **Числительные словами** — `One`, `Twelve`, `Thirty-first`: в китайском это иероглифы-цифры, в английском слова, и именно на этом ломается разрез глав (§4.4). - **Терминаторы предложения и сокращения**, где точка не кончает предложение (`Mr.`, `St.`, `vs.`) — ⚠ секция `en` в `backend/internal/lang/data/sentence-abbrev.txt` уже существует и её НЕ дублируй. ⛔ **ТРАНСЛИТЕРАЦИЯ — ОТДЕЛЬНЫЙ ВОПРОС, И ОТВЕТИТЬ НА НЕГО НАДО ЯВНО.** Канал транслитерации требует поимённо пиньинь-категории (`backend/internal/lang/langpack.go:531-540`): `palladius/initials` · `finals` · `yw` · `special_i` плюс три фонотактических. Английская практическая транскрипция — **другая система**, и в этой схеме она невыразима. Штатный механизм для источника, который НЕ везёт этот канал, в движке есть: `manifest.txt` объявляет, какие каналы источник ШЛЁТ (`backend/internal/lang/langpack.go:612`), и `D39.64` (строка реестра `docs/architecture/05-decisions-index.md`, пункт П4) ратифицировала ровно это намерение — источник без пиньинь-морфологии грузится без палладиевых файлов. ⭐ **Механизм подтверждён МОИМ чтением по пяти точкам, а не предположен** (`backend/internal/lang/langpack.go`): манифест отсутствует ⇒ включаются ВСЕ каналы (`:624`=`no manifest → every channel`); пустое объявление падает громко (`:644`=`manifest declares no channel`); файлы пары читаются ТОЛЬКО под гейтом канала (`:280`=`if channels[channelTransliteration]`); требование пиньинь-категорий стоит под тем же гейтом (`:531`=`if p.channels[channelTransliteration]`); свёртка хеша оверлея отсутствующий файл ТЕРПИТ (`:410`=`if !ok {` → `return nil`). ⇒ **`en/manifest.txt` с единственной строкой `channelsource-morphology` снимает пиньинь целиком, без единой строки Go.** ⛔⛔ **ЭТОТ ВЫВОД ОПРОВЕРГНУТ ЗАМЕРОМ 17.09 — ДВЕРИ НЕТ. Читай дальше, прежде чем строить на абзаце выше.** Сессия пака прогнала ПЯТЬ написаний манифеста юнит-пробой и продублировала живым `tmctl translate` на книге Кристоффа. Итог: манифеста, при котором английский источник грузится, **не завезя ЛИБО одиннадцать таблиц китайской формы, ЛИБО пиньинь, НЕ СУЩЕСТВУЕТ**. `channel⇥source-morphology` → `open …/en/surnames-single.txt: no such file`; `channel⇥transliteration` → `open …/en-ru/palladius.txt: no such file`; обе строки → снова `surnames-single`; только комментарий → `manifest declares no channel`. Моё чтение было верно про ПИНЬИНЬ (гейт канала его снимает) и неверно в практическом выводе: одиннадцать `srcFiles` требуются ровно тогда, когда объявлен канал морфологии, а не объявить ни одного нельзя. ⛔ **И заполнять одиннадцать таблиц по-английски ЗАПРЕЩЕНО — это решение, а не осторожность.** Их единственный потребитель — майнер имён, а его алфавит кандидатов только ханьский (`backend/internal/miner/miner_substrate.go:44`=`func isMinerHan(r rune) bool`) ⇒ **на английском источнике эти файлы не читает НИКТО**, и их заполнение не меняет ни одного байта поведения. Это «копия без предмета» дословно: она зеленеет и не делает ничего. Слово владельца было «уникально описать английский язык», а не «подделать китайскую форму, чтобы загрузчик замолчал». ⇒ **Практический путь на сегодня — §4.3 (путь данными), и он ПРОВЕРЕН сквозным прогоном.** Цена названа там же и обязана стоять в отчёте: английская книга едет с выключенным терминологом и выключенной банкнотой, то есть **без сквозной консистентности терминов — частичная потеря цели №1**. Это цена состояния дерева, а не выбор исполнителя. **Прежний абзац оставлен НАМЕРЕННО, а не вычищен:** он показывает, как выглядит вывод, сделанный чтением пяти верных точек и опровергнутый одним прогоном. Твоя работа устроена так же — **моё чтение говорит, что он работает; твой прогон говорит, что он работает НА САМОМ ДЕЛЕ, и это разные утверждения. ⚠ Разойдётся — это находка, пинг мне, и заказ меняется. ⚠ И назови в отчёте цену выбранного пути: без канала транслитерации передача английских имён в русский держится промтом и сидом, а не движком. **Советчик Fable 5 (§4.1) поднимается ИМЕННО ПОД ЭТО.** Слово владельца связывает его с данными прямо: он верифицирует «алгоритм исполнения И ДАННЫХ в бэкенде для английского». Спрашивай его не «хорош ли файл», а **«что английский язык обязан о себе сказать, чтобы перевод не стал translationese, и чего в моём описании не хватает»**. Его посылки проверяй деревом. Состав живой пары `zh-ru` — 11 файлов: `translator.md` · `editor.md` · `editor-mono.md` · `terminologist.md` · `classifier.md` · `translator-banknote.md` · `judge-selector.md` и `repair/` с четырьмя (`broken_word` · `dc1_fractional` · `dc1_time_units` · `latin_residue`). **РЕШИ САМА, с аргументом**, какие нужны английской паре. Мой приор, опровергаемый твоим замером: `dc1_fractional` и `dc1_time_units` — про китайские числительные и часы, предмета у латиницы нет. **Не копируй файл, у которого нет предмета: копия без предмета — вид лжи, которая зеленеет.** ⛔ **НО У ЭТОГО СОВЕТА ЕСТЬ УСЛОВИЕ, И БЕЗ НЕГО ОН ОПАСЕН.** `loadRepairTemplates` (`backend/internal/pipeline/repair.go:151`) возвращает `nil` сразу при выключенном гейте (`:152-154`), а при ВКЛЮЧЁННОМ отсутствие файла класса — **громкий отказ с именем пути** (`:170-172`). Дефолтный набор актуаторов — ровно два класса, и первый из них `RepairLatinResidue` (`:117-120`). Сегодня совет безопасен, потому что `gates.repair` не включён нигде: **0 из 5** файлов `backend/configs/*.yaml`; единственное упоминание в 26 конвейерах книг — комментарий, прямо говорящий «repair выключен». ⇒ **условие названо: совет держится, пока гейт выключен; включишь — отсутствие файла станет падением.** Пиши промты как переводчик, а не как инженер: английский источник несёт то, чего нет в китайском — артикли, время глагола как носитель сюжета, атрибуцию прямой речи внутри абзаца. Русские целевые данные НЕ трогаешь. ### 4.3. Стена 2 — гейт терминолога. ДЕЛАЙ РОВНО ТАК: сперва путь данными `backend/internal/pipeline/runner.go:364`: при `forWrite && Gates.Terminology.Enabled && r.pack == nil` — отказ. Замер со знаменателем: гейт включён в **трёх** конфигах из четырёх (`backend/configs/pipeline-c1.yaml:150`, `backend/configs/pipeline-arm-glm.yaml:60`, `backend/configs/pipeline-arm-mistral.yaml:67`); у `pipeline-c2.yaml` секции нет, но ⚠ это **не обходной путь**: `c2` — скелет ДРУГОГО ядра (generate-then-select), неисполнимый раннером фазы 0. ⭐ **Путь данными существует.** Гейты живут в ПАЙПЛАЙН-файле, который книга называет полем `pipeline:` (`backend/internal/config/book.go:79`). Замер: **все 23** `book.yaml` объявляют конвейер, из них **19** ⛔ **И СТЕНА, КОТОРОЙ НЕТ ВЫШЕ ВОВСЕ, А СТОИТ ОНА РАНЬШЕ ГЕЙТА ТЕРМИНОЛОГА** (замер сессии пака 17.09, `tmctl translate`): `mining.contrast_path` — частотный корпус ИСХОДНОГО языка, артефакт вне git. При пустом значении отказ идёт уже на ЗАГРУЗКЕ конфига (`backend/internal/config/pipeline.go:1197`), при непрочитанном файле — `EXIT=10`. Его единственный потребитель тоже майнер, то есть для английского он куплен впустую. ⚠ И перекос называет сам боевой конфиг: корпус контраста есть факт ИСХОДНОГО языка, а лежит он в пайплайн-файле, который по построению пар-агностичен. ⚠ **Шаг, без которого путь данными не проходит:** гасить надо не только `gates.terminology.enabled`, но и `gates.terminology.classify_types` — загрузчик отказывает на «classify_types is on but terminology.enabled is false». Плюс `gates.banknote.enabled` (иначе платим за выход, который никто не прочтёт). ⭐ **Путь ПРОВЕРЕН сквозным прогоном, а не обещан:** с этими тремя выключенными движок доходит до вызова модели (`stage=draft role=translator`, `estimate_usd=0.000000`) и встаёт только на отсутствии локальной модели на машине. **Никакого `configs/langpacks/en/` на этом пути не нужно вовсе.** Замер: **все 23** `book.yaml` объявляют конвейер, из них **19** называют `pipeline.yaml` и **4** — не-дефолтное имя. ⇒ конвейер английской книги с выключенным `gates.terminology` снимает отказ **без единой строки Go**. **Правку Go под ряд 347 НЕ делай без моего слова:** ряд **35** предупреждает, что снятие отказа без не-Han детектора «обещает больше, чем покупает» — банка на латинице всё равно не будет. ⚠ **Назови цену пути данными в отчёте:** без добытого банка нет сквозной консистентности терминов, то есть частично теряется цель №1. Вторую цену движок называет сам (`backend/internal/pipeline/runner.go:380`): канал банкноты при пустом паке **платит за выход, который никто не прочтёт** — гаси `gates.banknote` тем же конфигом. ### 4.4. Нарезка глав — предмет ПЕРЕ-ОПРЕДЕЛЁН. РЕШИ САМА форму, но популяцию бери движковую ⛔⛔ **ЧИТАЙ ЭТО КАК ПРЕДУПРЕЖДЕНИЕ О МЕТОДЕ.** Первая редакция промта утверждала «71 глава, из них 67 ПУСТЫ». Это было **ложно**, и ложно ровно потому, что число снято не на той популяции: я померил текст документа-цели `navPoint`, а движок читает **ГРУППУ**. `groupChapters` (`backend/internal/chunk/epubtoc.go:293-321`) в ветке `default` делает `last.docs = append(last.docs, i)` — каждый читаемый не-граничный документ приписывается к ПРЕДЫДУЩЕЙ главе; рядом стоит инвариант сохранения (`backend/internal/chunk/ingest.go:836-843`), а комментарий чтения гласит «Reading happens per GROUP so a chapter split across documents arrives whole». **Популяция движка, пере-снята мной его же правилом (python-реимплементация `resolveTOC`+`groupChapters`):** | | | |---|---| | глав | **71** · приписано документов **53** · **ПУСТЫХ 0** | | сумма прозы | **1 313 224** знака без пробелов ≈ 360 775 токенов — вся книга | | крупных глав | **6**: BOOK TWO 321 191 · BOOK ONE 283 459 · BOOK FIVE 227 308 · BOOK FOUR 213 052 · BOOK THREE 148 922 · BOOK SIX 115 310 | | крошечных (<200 знаков) | **65** | ⭐ **Следствие для меры владельца: срез СУЩЕСТВУЕТ УЖЕ СЕГОДНЯ.** Цель — 41 027 токенов (20 китайских глав). **BOOK THREE = 148 922 знака ≈ 40 912 токенов, промах −0.3 %.** Одна глава движка, без единой правки. ⇒ **нарезка НЕ блокирует эксперимент**, и заказывать её как блокер было бы ложью. **Настоящий дефект другой и он о КАЧЕСТВЕ:** шесть «глав» по 115–321 тыс. знаков — это не главы, а части книги, и 65 границ стоят на страницах-разделителях. Читатель получит шесть полотен вместо семидесяти одной главы. Это предмет ряда **283**. **РЕШИ САМА**, чинить ли это в паке; если чинишь — порог «сколько знаков делает главу главой» живёт в ДАННЫХ, а не в Go, и правило проверяется на ВТОРОЙ живой английской книге: `books/fifty_shades_1_en.epub` и `books/fifty_shades_1_en.txt` (909 093 байта; строк вида `Chapter …` в начале строки — **26**, разрывов страницы — **0**; оба числа мои, команда `command grep -cE '^[[:space:]]*Chapter '`). ⚠ **Соседний предмет, ТВОЙ вход, а не открытие по ходу — ряд 303:** не-CJK **TXT** режется в одну главу (лестница отдаёт `nil`, фолбэк — разрыв страницы, которых в живом английском txt ноль). Наша книга — EPUB, её это не задевает. **Назови границу явно**, иначе следующая смена прочтёт пак как «не-CJK нарезка починена». ### 4.5. Порог эха — ДЕНЬГИ. ДЕЛАЙ РОВНО ТАК: сперва замер, потом число `backend/internal/pipeline/disposition.go:465`: `const cjkEchoThreshold = 0.15`, применяется на `:403` к доле рун ИСХОДНОГО скрипта в выходе; доля считается от ВСЕХ рун, включая пробелы (`:472-484`). Конфиг-ручки нет. Для en→ru исходный скрипт — **латиница** (`backend/internal/lang/data/lang-script.txt`: `en latin`), а здоровый русский перевод английской книги несёт латиницу штатно. ⇒ 15 % достижимы без эха, а **ложный флаг ЭСКАЛИРУЕТ**, то есть покупает платный хоп за здоровый текст. ⛔ **ЧИСЛО 0.15 СНЯТО НЕ В ЭТОЙ КЛЕТКЕ** — оно унаследовано от китайского бенчмарка отказов. Измерь его на латинице ТЕМ ЖЕ кодом, что и движок, и покажи распределение. Носитель предмета — ряд **260**. ⛔ **Литерал порога ВХОДИТ в версию классификатора — пере-снято мной:** `backend/internal/pipeline/disposition.go:186` несёт `classify-v3-refusal+srcscript-echo015+…`, то есть подстроку `echo015`. ⇒ движение порога двигает ВЕРДИКТЫ и требует пере-снапшота. Порядок работ отсюда следует жёстко: порог трогается в ТОМ ЖЕ окне, что и нарезка, либо не трогается вовсе. ### 4.6. ⛔ ВТОРОЙ ДЕТЕКТОР ЛАТИНИЦЫ — его не было в первой редакции, и он противоречит §4.2 На каждом финальном чанке en→ru работает ВТОРОЙ счётчик латиницы, и он **не гейчен ничем, кроме цели**: `lintLatinResidue` (`backend/internal/checks/checkers.go:561`, порог `minLatinResidueLen = 3` на `:559`) вызывается из `RunCheapGates` (`backend/internal/checks/cheapgates.go:194`), а та бежит при `r.checkers.TargetActive()` (`backend/internal/pipeline/waverun.go:626` и `:760`) — для цели `ru` всегда. ⛔ **Его докблок (`backend/internal/checks/checkers.go:550-553`) утверждает ПРОТИВОПОЛОЖНОЕ тому, что §4.2 велит вписать переводчику:** целое латинское слово в не-латинской цели — утечка, «в русской цели латинское имя собственное **должно быть транслитерировано**», и правило объявлено **language-general** («Latin is not pair data»). ⭐ **Штатный механизм канон называет сам, и он НЕ порог:** «a legitimately-kept brand lives on the per-project allowlist, not on a „has a capital“ heuristic». ⇒ законная латиница английской книги едет через **аллоу-лист проекта**, а не через правку порога и не через промт переводчика. **ДЕЛАЙ РОВНО ТАК:** сперва замерь, сколько срабатываний даёт этот детектор на здоровом русском переводе английской прозы; потом решай. ⚠ И помни условие §4.2: пока `gates.repair` выключен, детектор только считает; включённый — становится актуатором с классом `latin_residue` в дефолте. ### 4.7. Ключи банка на латинице — РЕШИ САМА, но сперва измерь `backend/internal/text/norm.go` завершает нормализацию ключа `unicode.ToLower`. Для китайского это no-op; для английского — стирает признак, отличающий имя от обычного слова. Порог допуска не-Han ключа — 3 руны (`backend/internal/membank/memory.go:78-83`), `collisionProneKey` ловит только ≤3 (`:88-90`), а демоушен пост-чека Han-only (`backend/internal/membank/mempostcheck.go:151-156`) для английского не применяется никогда. ⚠ **Это подозрение, а не замер.** Первый шаг — измерить на нашем материале, сколько ключей фирят на обычных словах, и только потом решать. ### 4.8. Бюджет нарезки — РЕШИ САМА, и оценка законна вместо прогона `backend/internal/chunk/chunker.go:85-96`: `est_out = FertCJK·cjk + FertOther·other`; у английского плотных рун ноль. Последний фолбэк — 1.1978 / 0.3852 с комментарием в самом файле: это **zh-ru пар-калибровка, а не языко-нейтральная константа**. У `en-ru.yaml` блока `segmentation` нет. ⚠ **Ряд 14 держит этот предмет с оговоркой «калибровка ждёт боевого токенизатора», и рядом в той же строке предупреждает, что громкий segmentation-фолбэк ломает контракт коридора и голден-фикстуру на нём.** ⇒ калибровочный ПРОГОН деньгами §4.10 не выдан. **Заведи блок по ОЦЕНКЕ, назови её оценкой** — либо скажи «не делаю» с доводом. Правки Go это не требует. ### 4.9. Что в пак НЕ входит - **Не-Han майнер банка** (ряд **35**): майнер Han-only по построению (`backend/internal/miner/miner_substrate.go:44-63`), на латинице кандидатов ноль. Отдельный пак. - **Правка Go под ряд 347** — без моего слова (§4.3). - **Целевая латинописьменная пара (→en)** — ряд **259**. - **Транслитерационный канал** под пиньинь: требование категорий — `backend/internal/lang/langpack.go:531-540` (⚠ ряд 347 несёт устаревший адрес `:521-527`, который указывает в блок МОРФОЛОГИИ; ряд мой, пере-наведу я). - **Японская пара.** Мой замер по ходу: CJK-дефолт не режет ни одну из двух живых японских книг — ратифицирую отдельной нотой я, тебе не предмет. ⚠ Метод замера назову в ноте: движок сравнивает по `strings.TrimSpace` (`backend/internal/chunk/chunker.go:210`), а не по началу строки. - **`gates.repair` остаётся выключенным.** Включение — отдельное решение с ценой (§4.2, §4.6). ### 4.10. Деньги — и здесь ДВА разных предмета, которые нельзя путать Пак **$0** до момента, когда пара собрана. Тогда — **одна дымовая покупка** на ОДНОЙ главе (не на срезе), чтобы доказать, что путь доходит до файла. **Перед ней — пинг мне с ценой ДО траты:** оценка в токенах и долларах, потолок в `book.yaml` самой книги. Полный срез принадлежит ЭКСПЕРИМЕНТУ, не паку. ⛔ **Пере-снапшот — НЕ одно и то же на двух книгах, и первая редакция промта это смешивала.** `--resnapshot` дословно: «re-pin existing jobs to the current config snapshot (**re-translates already-paid chunks** — explicit consent)» (`backend/cmd/tmctl/invocation.go:131`), согласие — `--accept-rebill` (`:133`). ⇒ на **английской** книге пере-снапшот **$0**: оплаченных прогонов там нет, платить нечего. На **китайских стендовых** базах это ДЕНЬГИ и требует явного согласия — в пак они не входят. Голден-файл в дереве **один** (`backend/internal/pipeline/testdata/golden/capture.golden`). ⚠ Потолки банк-ролей **пожизненные**; на английской книге они тратиться не должны — если тратятся, это находка. ### 4.11. Стандарт работы Ценность продукта → архитектура → необходимый рефакторинг → без велосипедов. Сверка с индустриальным первоисточником прежде собственного изобретения. Книжный термин в общем пар-слое — утечка. ## 5. Самопроверка ИСПОЛНЕНИЕМ — и где у ЭТОГО пака мягко Мандат: **самопроверка исполнением, не перечитыванием.** Субагентов поднимать **разрешаю явно**. Тест на вырожденность: пункт, удовлетворяемый фразой «перечитал сам», — дефектен. ⛔ **Контроль исполнения — ПО ХОДУ, а не в конце** (слово владельца): раз в заметный кусок работы сверяй сделанное с ПЕРЕЧНЕМ ЗАКАЗА этого промта — списком, не по памяти. ⭐ **Прибор для этого, купленный приёмкой 17.09 (формулировка зоны):** собственные проверки не находят ОТСУТСТВУЮЩЕЕ, потому что знаменателем им служит твой же текст. Спросить у дерева, сходится ли отчёт, ты умеешь; спросить у отчёта, все ли предметы названы, — нет, список берётся оттуда же. ⇒ **сверяй перечень заказа с перечнем отчёта по СПИСКУ ЗАКАЗЧИКА** — тем же движением, что `comm -23` над пакетами батареи. **Мутации — часть заказа, а не только критерия приёмки.** Каталог сегодня `backend/cmd/tmmutate/mutations.json` (526 записей, 315 в гейте `battery`). Заведи записи на КАЖДУЮ новую ветку, которую пак создаёт (нарезка · порог эха · аллоу-лист · путь данными вокруг гейта), пометь их `battery` и прогони каталог ЦЕЛИКОМ, а не поодиночке. ⚠ Не сужай прогон через `-run`, чтобы влезть в память: подмножество не есть пакет. **Где у ЭТОГО пака мягко — пять мест; глубину и веер выбираешь ты:** 1. **Промты пары — единственное, что не ловится ни одним гейтом.** Батарея зелена при любом их содержании. 2. **Порог эха**: соблазн подвинуть число, не измерив; ошибиться можно в обе стороны. 3. **Популяция**, на которой снято любое число о главах: документ ≠ группа. Здесь я уже ошибся — проверь каждое своё число вопросом «на чём его читает ДВИЖОК». 4. **Детектор латиницы спрошен на ЦЕЛИ, а не на источнике** — гейт `TargetScriptNonLatin` отвечает про русскую цель и от английского источника не защищает. 5. **Путь данными вокруг гейта терминолога** снимает ОТКАЗ, но не даёт банка. Легко отчитаться «английский пошёл» и умолчать, что пошёл без механизма, ради которого гейт стоял. **Адверсариальный проход по СВОЕЙ готовой работе — обязателен**, отдельным заходом после объявления готовности. Мандат: «найди, что этот пак сломал и о чём умолчал». ## 6. Оси ревью — предметные, а не гигиенические 1. **Число снято на документе, а не на группе** (и шире: на популяции, которой движок не пользуется). 2. **Детектор спрошен на цели там, где предмет — источник** (и наоборот). 3. **Промт пары проверен НАЛИЧИЕМ файла, а не текстом**, который он производит. ## 7. Записка-план После §4.1 и до первой строки кода: что строишь, в каком порядке, чем предъявишь каждый пункт, плюс ВХОДНАЯ строка батареи числом. Пишешь в свою секцию `docs/PROGRESS.md`. ## 8. Заявление = команда Каждое число и каждая категорика отчёта — **с командой, которой получены**. Приёмка пере-ранит своим прибором; число без команды принимается «со слов» и так называется в акте. ## 9. Эхо-протокол старта До работы — **≤10 строк СВОИМИ словами**: скоуп · инварианты · что НЕ делаешь. ⚠ Дословный пересказ подтверждает канал, но не понимание, и повторяет ошибку промта вместе с ним. ## 10. Что не удалось и где прибор слеп — обязательная секция Две половины: **«что не получилось»** и **«что ты знаешь и не сказала»** — в форме «что невидимо · почему не чинила · чем закрывается». ⭐ **В коде названо, в отчёте нет — значит для следующей смены НЕ названо.** ## 11. Канал вопросов, право отказа, советчик Конфликт промта с кодом или доками — **пинг, а не интерпретация**. У тебя есть **право сказать «этого делать не надо»** с аргументом, и я это поощряю. ⛔ **Замер бьёт по посылке задачи — стоп и вопрос, а не артефакт под подпись.** Этот промт уже был исправлен четырежды по такому замеру. ## 12. Прямой канал Механизм — `CLAUDE.md` §«Связь между сессиями»: файл `/tmp/textmachine-channel`, свой блок дописываешь первым делом, чужие не трогаешь. ⚠ **Адрес из файла НЕ доказывает, что сессия жива: перед отправкой сверься с `ListAgents`.** Эхо-протокол (§9) шли первым действием. **Нужной роли нет ⇒ канала нет, это НОРМАЛЬНЫЙ случай: сессии подряд не опрашивать.** ## 13. Критерий завершённости — проверяемый - У **каждого** пункта заказа — исход: сделано · не делаю с доводом · пинг. Сверка по СПИСКУ ЗАКАЗЧИКА (§5). - Круги **сошлись**: последний не дал новых находок; прежние закрыты таблицей «находка → что сделано → **чем предъявлено**». - Гейт зоны (`make battery`) зелёный; названо, **что прогнано** и **сколько скипов** рядом с числом `ok`. ⚠ `go test ./...` без `-v` скипы не печатает — «ноль скипов» и «скипы не показаны» неразличимы. - Мутации: таблица полная, выжившие поимённо, новые записи помечены `battery`, каталог прогнан целиком. - Числа сняты **после последней правки**; промежуточные не цитируются. - Всё живое — **в ДЕРЕВЕ**, а не в письме. - Явное **«работа завершена, править не планирую»**. Без него пак считается идущим. ## Приложение. Ряды, на которые пак опирается Проверены мной по живому трекеру 17.09 (прибор прочёл 359 строк таблицы): | ряд | состояние | отношение к паку | |---|---|---| | **315** | ✅ **ЗАКРЫТ замером 06.09** | вход §4.1: `tmctl manifest` на ЭТОЙ книге уже дал 71 главу / 351 юнит / 356 чанков, `EXIT 0`, $0. Там же назван механизм `prompts_root` | | **303** | открыт, «скоро» | вход §4.4 (TXT-половина); ⚠ его граница: проверено по коду и фикстуре, живая не-CJK книга через ингест не прогонялась | | **283** | открыт, «скоро» | настоящий предмет §4.4 — структура глав для выдачи | | **347** | открыт, «когда-нибудь» | §4.3/§4.9; ⚠ несёт устаревшие адреса `langpack.go`, пере-наведу я | | **35** | открыт, «когда-нибудь» | §4.9: объясняет, почему снятие отказа не даёт банка | | **260** | открыт, «скоро» | §4.5 — ложный `off_target` на латинице-тяжёлом русском ЭСКАЛИРУЕТ | | **14** | открыт, «когда-нибудь», владелец | §4.8; ⚠ предупреждает о голден-фикстуре на коридоре | | **79 · 81 · 259** | открыты | соседние предметы, не трогать |