Move the closed chronicle of a landed pack into an archive slice, and give the three claims it carried alone a home that is not the archive.

This commit is contained in:
heaven 2026-09-11 00:24:20 +03:00
parent ab7b3c44a4
commit 7af35daf96
4 changed files with 629 additions and 599 deletions

View file

@ -3,7 +3,7 @@
> **Единственный трекер проекта.** Здесь живут строки, на которые доки, промты и D-ноты ссылаются словами «строка N» / «строка бэклога N»: **ID строки стабилен навсегда**, не перенумеровывается и не переиспользуется (D39.80). Правки — только через оркестратора; каждая петля обязана иметь диспозицию: решено / отложено-с-записью / отклонено.
> ⚠ **Это НЕ бэклог зоны `docs/`, а бэклог ПРОЕКТА.** У зон свои, с другими неймспейсами ID, и единый их строк не принимает (D39.84): платформа — [../platform/BACKLOG.md](../platform/BACKLOG.md) (`П-N`) и её регистр дефектов `platform/docs/DEFECT_REGISTER.md` (`PD-N`); фронт — [../frontend/docs/BACKLOG.md](../frontend/docs/BACKLOG.md) (`Ф-N`).
> ⚠ **Состояние проекта — не здесь.** Очередь, курс, CURRENT-STATE, состояние паков и живая хроника — шапка [PROGRESS.md](PROGRESS.md). Здесь только долг и его диспозиции.
> - **СЧЁТ ОЧЕРЕДИ на 10.09 (скриптом по таблице — `python3 docs/scripts/counts.py`; обновлять при каждом лендинге):** всего **287** строк · зона бэкенд **138** строго / **185** широко (⚠ колонки счётчик читает С КОНЦА — испр. D39.116) · **блокеров очереди 0** (236 закрыта D39.175; **371** — актом D39.233, **360** — актом D39.232, обе 10.09), платные прогоны разблокированы · «скоро» **136** (перечень — грепом по таблице, рукописный список снят D39.126) · гейт-строка эксп-22: 153 (плюс 150 — руки владельца; ⚠ 55 из гейтов СНЯТА — D39.198 п.5); строка 5 — остаток гейчен ре-пробой 74, носитель события теперь строка 188 (аудит D39.140); остальное «когда-нибудь». ⚠ Счёт — НИЖНЯЯ граница долга, не потолок (разбор — легенда таблицы ниже).
> - **СЧЁТ ОЧЕРЕДИ на 10.09 (скриптом по таблице — `python3 docs/scripts/counts.py`; обновлять при каждом лендинге):** всего **288** строк · зона бэкенд **138** строго / **185** широко (⚠ колонки счётчик читает С КОНЦА — испр. D39.116) · **блокеров очереди 0** (236 закрыта D39.175; **371** — актом D39.233, **360** — актом D39.232, обе 10.09), платные прогоны разблокированы · «скоро» **137** (перечень — грепом по таблице, рукописный список снят D39.126) · гейт-строка эксп-22: 153 (плюс 150 — руки владельца; ⚠ 55 из гейтов СНЯТА — D39.198 п.5); строка 5 — остаток гейчен ре-пробой 74, носитель события теперь строка 188 (аудит D39.140); остальное «когда-нибудь». ⚠ Счёт — НИЖНЯЯ граница долга, не потолок (разбор — легенда таблицы ниже).
> - ⚠ **Переезд 06.09 (D39.218):** таблица вынесена из `PROGRESS.md` ДОСЛОВНО и ни один ID не сдвинут — **с единственным исключением: две ячейки (строки 220 и 306) тронуты РОВНО в номере якоря `docs/scripts/counts.py:566`→`:569` и `:592`→`:595`**, потому что цель сдвинул этот же коммит; текст ячеек не менялся, длины равны. В `PROGRESS.md` на прежнем месте оставлен заголовок-указатель, поэтому ссылки «секция „Бэклог“» доезжают в один хоп.
## Бэклог (ЕДИНЫЙ, собран 26.07, актуализация 04.08 D39.99/D39.101; правки — только через оркестратора)
@ -319,7 +319,8 @@
| 395 | **DEV И ПРОД РАСХОДЯТСЯ В ДВАДЦАТЬ РАЗ ПО ВРЕМЕНИ НА СВОРАЧИВАНИЕ, И ЭТО НИГДЕ НЕ ОБЪЯВЛЕНО.** `platform/internal/ingest/supervisor.go`, греп `WaitDelay` — тридцать секунд на dev-пути; `platform/internal/runner/runner.go`, греп `stopGrace` — десять минут на боевом. Один и тот же движок против тех же платных провайдеров получает на свёртку полминуты или десять минут в зависимости от пути запуска. Расхождение само по себе может быть законным, но оно НЕ НАЗВАНО, и dev-замер «успевает свернуться» ничего не говорит о боевом (и наоборот) | платформа | когда-нибудь | оба числа названы в одном месте с доводом, почему они разные, либо сведены | улов платформенной сессии, 10.09 |
| 396 | ⛔ **ГЛАВНАЯ РАЗВИЛКА «ПРАВИЛЬНОГО ВОЗОБНОВЛЕНИЯ»: платформа ПЕРЕЗАПУСКАЕТ прогон, вышедший с кодом остановки БЕЗ записанного намерения.** `platform/internal/runs/reconcile.go`, греп `interruptedBySomeoneElse`. Решение осознанное и с записанным доводом (перезагрузка хоста против ручного `systemctl stop`, асимметрия цен), поэтому строка не о дефекте. ⚠ Но инвариант `D39.240` («правильно возобновить») обязан пересмотреть эту развилку ЯВНО, а не унаследовать: сегодня она означает, что прогон, остановленный мимо продуктовой двери, будет поднят заново и продолжит тратить. Названо платформенной сессией как то, что новый пак не должен взять по умолчанию | платформа | скоро | поведение при коде остановки без намерения ПЕРЕ-решено под инвариант корректного возобновления, а не унаследовано | улов платформенной сессии, 10.09 |
| 397 | **ПЯТЬ ОТКРЫТЫХ РЯДОВ РЕЕСТРА ПЛАТФОРМЫ ПРО ХОЛДЫ И ОСТАНОВКУ — ОДИН ПРЕДМЕТ, А НЕ ПЯТЬ РАЗРОЗНЕННЫХ.** Их печатает собственный гейт зоны как тревогу. Прямо по предмету остановки и возобновления: **PD-418** (у расчётной строки живого прогона нет ручки, а рантбук обещает оператору обратное) · **PD-244** (единственный выход расчёта, оставляющий холд открытым МОЛЧА) · **PD-162** (книга с удалённым каталогом принимает прогон и заклинивает его навсегда с открытым холдом) · **PD-465** (заявка на спавн коммитится ДО подъёма юнита, третий способ уехать под доказательством не ловится) · **PD-217** (книга с незакрытым холдом блокирует апгрейд движка бессрочно). ⇒ под инвариантом `D39.240` это готовый предметный список «не оставить мусор», уже приоритизированный реестром зоны | платформа | скоро | пять рядов закрыты ОДНИМ предметом либо явно разведены как разные | улов платформенной сессии, 10.09 |
| 398 | ⛔ **ПРОГОН, ВЫШЕДШИЙ БЕЗ МАРКЕРА, ПЕРЕЗАПУСКАЕТСЯ БЕЗ ВСЯКОГО ОГРАНИЧЕНИЯ — капа попыток у платформы НЕТ.** Юнит кончился, маркера нет (сломан `ExecStopPost`, повторная перезагрузка) → после льготного окна спавна и без записанного намерения платформа считает состояние свежим и ПЕРЕЗАПУСКАЕТ: новый холд, новый спавн. На ДОЧИТАННОЙ книге движок выходит сразу и снова без маркера ⇒ цикл повторяется каждым проходом свипа. Замер: `MaxAttempts` в `platform/internal` вне тестов — **7 хитов, все в `jobs.go` и все про очередь**, ни одного про попытки прогона (контроль: слово `restart` в `platform/internal/runs/reconcile.go` есть и читается). ⚠ И тревога МОЛЧИТ: счётчик отсрочек очищается «уликой» каждого рестарта, поэтому порог зависания недостижим. ⚠ **Честная граница (Fable 5, 10.09): путь ЗАМЕРЕН чтением, сам бесконечный цикл ВЫВЕДЕН, прогоном не предъявлен** | платформа | скоро | у перезапуска без маркера есть потолок, а его исчерпание видно оператору | разбор старшего коллеги по инварианту `D39.240`, 10.09 |
| 399 | **ПЛАТЯЩИЙ ПРОГОН МОЛЧА ЗАМИРАЕТ В ИНТЕРФЕЙСЕ: проекция ПАРКУЕТСЯ при ре-спавне той же попытки.** Курсор встречает чужой хендшейк, проекция останавливается до конца попытки — `platform/internal/runs/reconcile.go`, греп `ErrForeignStreamAhead`; комментарий там же признаёт: «the "stranger" may be this very run, alive and writing». ⇒ прогон жив, платит и пишет, а прогресс не двигается. **У состояния «запаркована» нет носителя** — ни столбца, ни счётчика; репэйр-канал чинит оценку времени и свежесть, но не прогресс. Пользователь видит замерший экран без объяснения | платформа | скоро | у запаркованной проекции есть носитель состояния, и пользователю сказано, что прогресс отстал, а не остановился | разбор старшего коллеги, 10.09 |
| 398 | ⛔ **ПРОГОН, ВЫШЕДШИЙ БЕЗ МАРКЕРА, ПЕРЕЗАПУСКАЕТСЯ БЕЗ ВСЯКОГО ОГРАНИЧЕНИЯ — капа попыток у платформы НЕТ.** Юнит кончился, маркера нет (сломан `ExecStopPost`, повторная перезагрузка) → после льготного окна спавна и без записанного намерения платформа считает состояние свежим и ПЕРЕЗАПУСКАЕТ: новый холд, новый спавн. На ДОЧИТАННОЙ книге движок выходит сразу и снова без маркера ⇒ цикл повторяется каждым проходом свипа. Замер: `MaxAttempts` в `platform/internal` вне тестов — **7 хитов, все в `jobs.go` и все про очередь**, ни одного про попытки прогона (контроль: слово `restart` в `platform/internal/runs/reconcile.go` есть и читается). ⚠ И тревога МОЛЧИТ: счётчик отсрочек очищается «уликой» каждого рестарта, поэтому порог зависания недостижим. ⚠ **Честная граница (Fable 5, 10.09): путь ЗАМЕРЕН чтением, сам бесконечный цикл ВЫВЕДЕН, прогоном не предъявлен****УСИЛЕНО пере-замером платформенной сессии 11.09: естественного ограничителя в ДЕНЬГАХ нет.** Она искала его и не нашла: перезапуск сперва РАССЧИТЫВАЕТ старую попытку, потом берёт новый холд; попытка ничего не потратила (движок выходит сразу) ⇒ холд возвращается целиком и берётся равный новый ⇒ **цикл денежно-нейтрален на итерации и балансом не останавливается**. ⚠ Но цена НЕ нулевая: каждая итерация пишет строки леджера — расчёт и холд, — то есть цикл производит именно тот мусор, против которого заведён инвариант `D39.240`. ⭐ И материал для потолка уже есть: номер попытки инкрементируется каждым пере-открытием, значит капа выражается «номер больше N» БЕЗ новой колонки (доказательство спавна для этого не годится — оно на попытку, а перезапуск открывает новую) | платформа | скоро | у перезапуска без маркера есть потолок, а его исчерпание видно оператору | разбор старшего коллеги по инварианту `D39.240`, 10.09 |
| 399 | **ПЛАТЯЩИЙ ПРОГОН МОЛЧА ЗАМИРАЕТ У ПОКУПАТЕЛЯ, КОГДА ПРОЕКЦИЯ ПАРКУЕТСЯ. ⚠ Строка ПЕРЕ-ПИСАНА 11.09: первая редакция утверждала, что у состояния «запаркована» нет носителя — ЭТО БЫЛА МОЯ ОШИБКА, носителей ЧЕТЫРЕ**, и пере-снято их платформенной сессией: столбец `run_attempts.parked_at` (миграция `00034_spawn_proof_and_park.sql`) · писатель `Store.MarkParked` (`platform/internal/pgstore/runs.go`) · чтение на выписке (`LiveRun.Parked`) · **операторский гейдж** `parked_attempts` (`platform/internal/metrics/metrics.go`), плюс операторский листинг и лимитированная по частоте строка лога (`sayParked`). Если бы строка ушла в заказ как написана, пак пошёл бы строить построенное — ровно класс «условное закрытие», который мы вычищаем из доков. **⇒ ЖИВАЯ половина — ПОЛЬЗОВАТЕЛЬСКАЯ, и только она:** оператор видит парковку четырьмя способами, а ПОКУПАТЕЛЬ видит замерший экран без объяснения. Механизм: курсор встречает чужой хендшейк и проекция останавливается до конца попытки (`platform/internal/runs/reconcile.go`, греп `ErrForeignStreamAhead`), причём комментарий там сам признаёт: «the "stranger" may be this very run, alive and writing» | платформа | скоро | пользователю сказано, что прогресс отстал, а не остановился — тем же каналом, которым он видит прогресс | разбор старшего коллеги + пере-замер платформенной сессии, 1011.09 |
| 400 | **ПРАВКА БАНКА ЛЕГЛА, ПЛАТФОРМА УМЕРЛА ДО ЗАПИСИ О НЕЙ — СЛЕДУЮЩИЙ ПРОГОН ВОЗЬМЁТ ХОЛД И УМРЁТ НА ГАРДЕ.** `platform/internal/runs/bank.go`, греп `RecordBankMove`: ветка ошибки стора обработана (клиент пере-шлёт, сходится), а смерть ПРОЦЕССА между применением правки и записью факта канала не имеет. Цену называет собственный комментарий кода: отметка о движении банка остаётся пустой ⇒ следующий прогон допускается без пере-снапшота ⇒ умирает на снапшот-гарде уже ПОСЛЕ взятого холда (`PD-425`). ⚠ Прямо на предмете `D39.240`: «не оставить мусор» и «правильно возобновить» — это ровно оно | платформа | скоро | смерть между правкой банка и записью о ней не приводит к взятому холду и умершему прогону | разбор старшего коллеги, 10.09 |
| 401 | **МУСОР НА ДИСКЕ ПОСЛЕ ОБРЫВА: три носителя, ни один не подметается.** **(а)** артефакт сборки при смерти платформы посреди неё остаётся на месте — перечень удаляемого берёт только строки с путём (`platform/internal/exports/exports.go`, греп `Unlinked`); **(б)** временные файлы движка чистит ТОЛЬКО следующая сборка того же идентификатора, которой при обрыве не будет; **(в)** частичный бэкап движка ложится под именем, которого платформа не знает (`platform/internal/runner/backup.go`). ⚠ Отдельно, инертно, но противоречит леджеру: отметка о расчёте может остаться пустой навсегда, если расчёт прошёл, а её запись — нет; читателей столбца вне тестов **0** (греп: только писатели и комментарии) | платформа | когда-нибудь | обрыв не оставляет на диске файлов, которых никто не подметёт, и отметка о расчёте не расходится с леджером | разбор старшего коллеги, 10.09 |
| 402 | **ТРИ УТВЕРЖДЕНИЯ, КОТОРЫЕ ВЫНОС ХРОНИКИ В АРХИВ ОСТАВИЛ БЫ БЕЗ НОСИТЕЛЯ — заведены ТЕМ ЖЕ движением, что и вынос** (условие ока старшего коллеги на дифф, `D39.239` п.4). **(а) Стейл-упоминания снятого маркера `⟨проверить⟩` ВНЕ движка** — вынесенный отчёт называл `platform/internal/runs/spawn.go`, `platform/internal/runs/reconcile_test.go`, `platform/docs/DEFECT_REGISTER.md` (PD-277) и `eval/pilot/memory_eval.py`; все места живы сегодня, плюс `eval/pilot/kana_precision.py`. ⚠ **Стейл ли они — НЕ доказано:** в движке маркер стоит в **10** не-тестовых носителях и 7 тестовых, то есть снят он, судя по числам, только с провода инъекции. Проверять и чинить — чужим зонам (платформа, полигон), пинги им отправлены. **(б) Следствие ФЧ-7: прогон, который УПАЛ поверх потолка, приезжает `paused` с пустым кодом выхода** — по терминам «упал поверх потолка / ФЧ-7 / exit_code nil» носителей **0** в журнале решений, едином бэклоге и регистре платформы (PD-113 — исходный класс, не это следствие). Код платформы принимает это как конструкцию (греп `survives ANY exit`), но выбор «краш невидим за `paused`» нигде не записан как ПРИНЯТЫЙ. **(в) Две границы «не проверено» заланденного пака, у которых нет носителя нигде:** качество рода не измерено на живой книге; цена банкового контура в `c1` на реальной книге не мерена | доки | скоро | каждое из трёх либо получило носитель в своей зоне, либо признано неверным и снято | условие ока на вынос хроники 11.09 |

View file

@ -240,6 +240,15 @@ D23.3). Владельцу на решение: деньги сверх мело
от него. Настоящие развилки сессий эскалируй быстро и решай сам; сессии, приносящие развилки вместо
тихих девиаций, — поощряй.
### Вынос блока в архив: якорь НИЖЕ разреза уезжает вместе с ним
⛔ Проверять надо не «есть ли якоря В ВЫРЕЗАЕМОМ диапазоне», а **«есть ли якоря с номером ≥ начала разреза»**:
всё, что стояло ниже, сдвигается на длину вырезанного и становится битым молча. Замер 11.09 при выносе
196 КБ из живого журнала: якорей вида `PROGRESS.md:NNN` во всём живом дереве — **25**, максимальный номер
**1190**, начало разреза — 3009 ⇒ класс не сработал только потому, что все двадцать пять оказались выше.
⚠ И греп по `docs/` для этого мало: канон велит НЕ исключать `archive/architecture/` — там тела закрытых
эр журнала решений, и они тоже ссылаются.
### Приписывание — проверяется у ИСТОЧНИКА, а не пересказывается
⛔ **Находка, пришедшая через третьего, не заводится строкой с именем ПЕРВОГО, пока первый её не подтвердил.**

View file

@ -3006,602 +3006,14 @@ polygon, `mined_delta`/`mined_rejects` — в 17 конфигах из 31, по
---
## Пункт 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 мс — то есть запрос был выпущен и, скорее всего, оплачен. Латентность разводит два случая (2031 мс против 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**. Протухли четыре МОИ ЖЕ записи, чьи якоря увезли рефакторы кругов 23: `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=<usd>`; одна формулировка 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=<usd>` несёт `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 '<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=<usd>` — требует «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+estimateceiling`, поле `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-тер риск (б) назван мягче, чем он есть: счётчики не «получают новую форму», а
врут по шести полям из семи.
## Отчёты пака «закон банка честно» и петли `D39.191` — ВЫНЕСЕНЫ В АРХИВ 11.09
> Хроника закрытых пунктов — **строки 210 · 113→46 · 134 · 140 · 184(а)** и дофикс чужого пака (номера названы
> здесь намеренно: греп по номеру строки обязан приземляться на указатель, а не мимо), разметка свободы, самопроверка, «что не удалось»,
> дофикс приёмки 04.09, круги 2 и 3 петли `D39.191`) уехала в
> [`archive/PROGRESS-2026-09-04-07-bank-law.md`](archive/PROGRESS-2026-09-04-07-bank-law.md) — 196 КБ, 14 секций.
> Вынесено по мандату владельца на снос протухшей прозы (`D39.239` п.4); ссылок извне на блок было **0**.
> Живое из этих отчётов живёт нотами и строками трекера, а не здесь.
## Полигон

View file

@ -0,0 +1,608 @@
# Архив хроники — отчёты пака «ЗАКОН БАНКА ЧЕСТНО» и петли `D39.191` (закрыты 0407.09)
> ⚠ **АРХИВНЫЙ СРЕЗ. При онбординге НЕ читать — только по конкретной ссылке.** Вынесено из живого
> `docs/PROGRESS.md` 11.09 по мандату владельца на снос протухшей прозы (`D39.239` п.4). Здесь лежат
> отчёты ЗАКРЫТЫХ пунктов: шесть пунктов наряда (строки 210 · 113→46 · 134 · 140 · 184(а) и дофикс
> чужого пака), разметка свободы, самопроверка, «что не удалось», дофикс по приёмке 04.09 и два круга
> петли `D39.191` — второй не замкнулся, третий замкнулся по содержанию, но не по условию.
> ⛔ **Ничего отсюда не исполняется.** Всё живое из этих отчётов ратифицировано нотами и заведено
> строками трекера; сюда вынесена ХРОНИКА, а не долг. Проверено перед выносом: ссылок на этот блок
> извне живого журнала — **0** (контроль: якорей вида `PROGRESS.md:NNN` в живых доках 17, ни один не
> указывает в этот диапазон; секции по имени вне журнала — 0 хитов на каждую из четырёх проверенных).
## Пункт 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 мс — то есть запрос был выпущен и, скорее всего, оплачен. Латентность разводит два случая (2031 мс против 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**. Протухли четыре МОИ ЖЕ записи, чьи якоря увезли рефакторы кругов 23: `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=<usd>`; одна формулировка 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=<usd>` несёт `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 '<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=<usd>` — требует «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+estimateceiling`, поле `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-тер риск (б) назван мягче, чем он есть: счётчики не «получают новую форму», а
врут по шести полям из семи.