# Журнал прогресса > **⟶ ТЕКУЩЕЕ СОСТОЯНИЕ** (на 2026-09-17, голова D39.266 — КУРС: движок и платформа до «работает и отдаёт результат», фронт ЗАМОРОЖЕН и P7 его НЕ размораживает (D39.147). **ОЧЕРЕДЬ №23** (единственный носитель — здесь; роль передана 06.09, №22 закрыт нотой передачи D39.217; ⚠ испр. 06.09: коммит передачи `c992ee5` бампнул голову и НЕ тронул номер — гейта на номер очереди нет вовсе, `counts.py` сверяет только голову, поэтому носитель разошёлся молча). ⚠ **ЗАКАЗ ВЛАДЕЛЬЦА 01.09 — ИСПОЛНЕН, испр. 08.09 (висел как «первым» неделю после исполнения):** (0а) ревизия документации на протухшее ОТРАБОТАНА 01.09 воркфлоу `docs-staleness-revision-A` (15 срезов), провенанс находок — `D39.185`; (0б) планы доработок в бэкенд и платформу — исполняются ПАКАМИ, за 07–08.09 закрыты два движковых (`D39.225`, `D39.226`); (0в) вынос неактуального в архив идёт батчами `DOC_CLEANUP_PLAN.md` (Б14/Б15/Б17 живы). ⇒ строка ниже — не заказ, а история: (0а) ревизия документации на ПРОТУХШЕЕ — по всем зонам; (0б) планы доработок в БЭКЕНД и ПЛАТФОРМУ; (0в) вынос неактуального в АРХИВ (`docs/archive/`, `platform/docs/archive/`) — за сутки 31.08 закрыто много, и часть носителей стала историей. ⚠ Трезвость по масштабу (пере-считано 02.09): **95** живых доков в `docs/` (⚠ испр. 17.09 вечером: стояло **98**, и это был ЛОЖНЫЙ литерал, а не потеря файлов — сверка дерева со срезом головы предписанной здесь же командой дала 95 в ОБЕИХ сторонах, ни одного файла не ушло и не пришло; ошибся сам пере-счёт, а прибор это число не сторожит и потому ложь прожила день. В 95 уже входит промт выдачи №14; пере-счёт после выноса каталога консилиума; прежние 97 разошлись с фактом 144 и это заметил ревизор, а не гейт) (пере-счёт 04.09: `find docs -name '*.md' -not -path 'docs/archive/*' | wc -l`), 8 в `platform/docs`, **12** в `backend/docs`, **7** в `frontend/docs` (испр. 17.09: стояло 9) — ⚠ ⚠ испр. 11.09: из 97 ВРЕМЕННЫХ **три** (`DOC_CLEANUP_PLAN`, живой до закрытия батчей Б14/Б15/Б17); два прежних временных уехали в `archive/reports/` 02.09; счёт бэклога — бюллетенем ниже, открытых рядов регистра платформы — 109 (major 0), всего рядов 469 (пере-счёт `python3 docs/scripts/counts.py`; с 04.09 оба числа под гардом `--check`, прежние 95/3 разошлись молча) ⚠ (ревизией 02.09 ряды **154** и **157** переведены из «скоро» в «когда-нибудь»: их гейтом стоял первый холодный прогон, он ОТРАБОТАЛ 31.08 и оба предусловия оказались другими — разбор в самих ячейках, ни одна НЕ закрыта). ⚠ Числа доков `counts.py` НЕ сторожит — при переносе файлов пере-считывать руками командой `find docs -name '*.md' -not -path 'docs/archive/*' | wc -l`. ⚠ И предупреждение о МЕТОДЕ, купленное сменой №21: «выглядит протухшим» ≠ «протухло». Три факта оркестратора опровергнуты ЗАМЕРОМ сессий, а якоря `15-money-path.md` в девяти случаях из двенадцати РОДИЛИСЬ верными и сгнили дрейфом — то есть ревизия обязана быть исполнением, а не чтением. ⚠ **ОЧЕРЕДЬ, унаследованная от №21** (три лендинга 31.08 — секция «СОСТОЯНИЕ ПАКОВ» ниже): **(1) ~~РАЗРЫВ ЦИКЛА~~ ЗАМКНУТ ЖИВЬЁМ 04.09** — пользователь получил EPUB настоящего ПЛАТНОГО перевода ЧЕРЕЗ API, `epubcheck` 5.3.0 на СКАЧАННОМ файле 0/0/0/0 (книга `bk_SS5VES2JELESJSTR`, потрачено $0.278319 из гранта $0.60 при потолке пака $1.5, санкция D39.189). Дверь выдачи построена и проверена исполнением: `202`+`Location`, поллинг с `Retry-After`, Range 206 · второй клиент 200 · аноним 401 · чужая книга 404, TTL с GC, идемпотентность третьего создающего вызова. Все ТРИ сценария строки 216 предъявлены живьём (подпись банка · halt на потолке с exit 4 · `409 run_not_resumable/ceiling_reached` и лечение новым прогоном). > ⛔ **ПЯТЬ ПОТОКОВ РАБОТЫ — состояние на 07.09 (пере-снято лендингами смены №23).** > **(1) ПОЛИГОН — «ремонт прибора»** (`docs/POLYGON_INSTRUMENT_REPAIR_SESSION_PROMPT.md`, строки 319 · 300 · 265 · 143): > ⚠ **ЕДИНСТВЕННЫЙ ПОТОК, НЕ СДВИНУВШИЙСЯ ЗА СМЕНУ — сессия по промту так и не стартовала.** Блокирующая линза > слепого чтения меряет верность ЧЕРНОВИКУ, а судимой руке предписано отходить от него по исходнику (`D39.215` п.3) > ⇒ **фаза Д ПРИОСТАНОВЛЕНА до его лендинга**: иначе покупаем числа, которые ничего не значат. > **(2) БЭКЕНД — «закон банка честно»: ✅ ЗАЛЕНДЕН 07.09, акт `D39.222`** (`5092ae3` + `0ae9e8a` + `bc03fc0`). Строки > 267 и 318 закрыты, у 320 исполнена половина (а). Шесть кругов самопроверки, 43 находки в собственной работе. > Живой остаток зоны — строки **333–339** (шов-близнец и пять описаний, лгущих оператору) и 320(б). > **(3) ПЛАТФОРМА — «деньги и правда»: ✅ ЗАЛЕНДЕНА 07.09, акт `D39.221`, контрактный минор `0.13.0`** (`fda0679` + > `3d90943`). Строки 285 · 305 · 325 закрыты. ⚠ **Синхронный разрез приёма принят ПОСТРОЕННЫМ, НО НЕ ГОТОВЫМ** — > сработало правило остановки (9 major из 11 в одном механизме), десять пунктов несёт строка **332**; ложный > инвариант бюджета заландён осознанно (окно лжи 8 секунд при дефолте в 16 минутах, ломается идемпотентность). > **(28) ✅ ПЛАТФОРМЕННЫЙ ПАК «ПРОГОН НЕ ВРЁТ О СЕБЕ» ПРИНЯТ — акт `D39.265`, контрактный минор 0.17.0.** 32 пути, $0. Прогон перестал врать на трёх осях: у перезапуска появился ПРЕДЕЛ (дефолт 20, ручка деплоя, проверка ВМЕСТО нового холда), платящий видит, что числа ОТСТАЛИ, а прогон идёт и тратит (`Run.progress_lagging`), и на проводе названа величина согласия на пере-оплату вместе с её ПРОВЕНАНСОМ (`Run.rebill_consent_micro_usd` — собственный холд прогона, а не проекция стоимости пере-делки). Смерть между правкой банка и записью о ней закрыта миграцией `00037`: намерение ставится ДО глагола и снимается только против расписки. ⭐ Лучшее в паке — не механизмы, а ПРИБОР: условие «зелёная база», которое ряд 486 просил построить, в первый же прогон поймало дефект ЭТОГО ЖЕ пака и вернуло пять записей как НЕ ИЗМЕРЕННЫЕ, а не ложным RED. **Ряды:** 398 · 399 · 400 · 486 закрыты работой, 394 и 396 — ПЕРЕ-РЕШЕНИЕМ («мы сами перестали перезапускать» — другая ось, чем «стоит ли клиенту повторять»; словарь причин отказа, закрытый в ТРЁХ носителях и не стерегомый ничем, теперь под гейтом), 416 — платформенной половиной; заведены **493** и **494**, дополнен **484**. ⛔ **Гейт зоны на финальном дереве КРАСЕН и назван границей, а не зеленью:** экземпляр ряда 484, оба упавших теста живут в чистом `HEAD`, механизм — бюджет записи, который фикстура ставит себе сама. Изолированно 4 круга зелёных из 5, пятый завис на пуле — округлять до «зелен всегда» я не стал. **Числа приёмки сняты мной:** кампания 26/25/1/0 на отдельном корне её же харнессом, копия вернулась байт-идентичной, все 26 целей на месте; деньги $0 двумя путями (трата за 17.09 — 0 при контроле 8 ключей; вызовов — 0 при контроле 336 записей). ⚠ **Две мои ошибки в акте:** взял себе правку канона, которая принадлежит зоне (откатил, дифф 0 строк), и неточно сформулировал §4.1 промта. ⚠ Плюс класс, купленный смены: два измерителя в ОДНОМ стенде портят числа молча, и порча выглядит как свойство предмета. > > **(27) ✅ ТРИ АКТА 17.09 И ПАК ОЧЕРЕДИ №14 ВЫДАН — `D39.262` · `D39.263` · `D39.264`.** Платформенный пак читателя предложений банка принят (`ffd3751`, 21 путь, контракт 0.16.0): на экране подписи было 0 терминов при 69 и 66 предложенных, стало 69 и 66. Бэкенд-пак лестницы попытки принят (`10d245a`, 18 путей, $0): петля вынесена в общий контур, банк-роли подключены к вердикту, который движок вычислял и выбрасывал. Нотой `D39.263` закрыт остаток консилиумных расхождений: производитель проактивного `hidden` — ЧЕЛОВЕК через сид; условия Д-6/Д-17 ПРИОСТАНОВЛЕНЫ, а не отменены; Д-3 ОТКЛОНЁН вторым отказом. ⭐ **Заказан главный механизм банка:** промт «РЕШЁННОЕ НЕ ПЕРЕ-СПРАШИВАЕТСЯ» выдан сессии `textmachine-main-57` (выдача №14), эхо принято, записка-план в секции «Бэкенд» ниже. Состав сузился против проекта консилиума: N-4 и Б-5 ПОСТРОЕНЫ паком `D39.257`, N-6 гейчен разморозкой фронта (ряды 214 · 221), Б-2 протух, а N-3 и стратифицированный отбор вынесены наружу со своими замерами. ⛔ **Исправлены два МОИХ ложных утверждения, которыми уже пользовались бы другие:** ряд 449 и этот план писали «гейт снят словом владельца» — слово дало санкцию на ЗАМЕР M4, а гейт принадлежит `D39.50` и владельцем не затрагивался; пинг зоне бэкенда нёс адреса, ВЫЧИСЛЕННЫЕ сдвигом, вместо найденных поиском. ⚠ И третье, найденное советчиком уже после выдачи: материал замера в промте указывал на другую КНИГУ (`book_id` `guzhenren-coldrun-v16`, глоссарий 53) вместо платного прогона A (глоссарий 69, $0.419423) — исправлено релеем, сессия подтвердила эхом. **Якоря:** пере-нацелено 20, линтер 42 → 17; остаток назван поимённо (8 с принятой диспозицией, 4 в чужих зонах, 5 закрыты эрратой 17.09-и и четвёртой пометкой в `research/35`). Заведён ряд **490** — страж разрыва окон глав у банковых строк. > > **(26) ✅ ДВА ПАКА 16.09 ПРИНЯТЫ, БАНК ПЕРЕЕЗЖАЕТ В КНИГУ-ПРОДОЛЖЕНИЕ — акты `D39.253`–`D39.257`.** `D39.253` — консилиум банка памяти закрыт, итог `research/35-bank-memory-consilium.md`; `D39.254` — пять решений владельца по нему. `D39.255` — движковый пак «КУПЛЕНО — ЗНАЧИТ ДОСТАВЛЕНО» принят (29 путей, $0): ⛔ три опубликованных ключа качества уехали смыслом (`ProcessedUnits`, черновиковый и эдит-числитель эха), и пере-классификация `cancelled` меняет счёт слотов на книгах, которые УЖЕ в поле — оба названы остатком, не умолчаны. `D39.257` — пак «БАНК ЗА $0» принят: громкий отказ, когда цель есть, а инъекционных текстов нет, — ДО первой траты; отказ роли перестал ехать в банк законом и разведён с мусором; два предиката «спорный» построены без платного потребителя. ⭐ Судилось ПЯТЬЮ приборами (батарея 24/24, мой собственный мутационный прогон, три оси аудита вне сдачи, пере-снятие чужих чисел, денежная ось: 0 платных путей при контроле 192 прочитанных файла). ⭐ **`D39.256` — решение владельца: банк переезжает в КНИГУ-ПРОДОЛЖЕНИЕ ПОДПИСАННЫМ ПЛЮС РЕШЁННЫМ ДВИЖКОМ**, стройка двухзонная — ряд **461**. ⚠ **Две эрраты того же дня, обе к моим собственным утверждениям:** 16.09-а — число «48 конфигов книг» я взял из чужого отчёта, не пере-мерив (верно 24), и каталожный прогон закрыт числом 267/267; 16.09-б — ноты `D39.256` и `D39.257` утверждают ПРИЧИНУ, которой замер не давал («причина смен передачи — якорь»), измерено лишь отсутствие новой улики во ВХОДЕ ⇒ причина остаётся ГИПОТЕЗОЙ, гейченной рядом **466**. Ряды: закрыты **291** · **379** · **441** · **460**; заведены **457–468**; **445** сужен наполовину. > **(25) ✅ ПЛАТФОРМЕННЫЙ ПАК «ОТВЕТ ДВЕРИ НЕ ЗАВИСИТ НИ ОТ ПОРЯДКА, НИ ОТ ВЕЗЕНИЯ» ПРИНЯТ С ДВУМЯ ДОФИКСАМИ, акт `D39.250`**, контрактный минор **0.15.0** (27 путей, 24 новых теста, $0). ⭐ Предмет ПЕРЕ-ОПРЕДЕЛЁН замером зоны ДО первой правки: не редкая гонка под нагрузкой, а ОРДИНАРНЫЙ путь — любой резюм живого прогона отвечает 409 детерминированно. ⛔ **Оба денежных предохранителя оказались проверены не тем прибором** (гард судил шаблон, а проба рендерит свой $0-пайплайн строкой выше; рецепт проверен текстовым сканом вместо загрузчика — `EXIT=10`), и ответ лежал в дереве комментарием того же хелпера. ⭐ Лечение — СНОС рецепта, а не починка: `П-22` и `П-23` схлопнулись, мина стережётся по умолчанию. Закрыты `PD-448` · `PD-466` · `PD-162` · `PD-139` · `П-22` · `П-23`; живое — эскроу `П-18` и одно названное слепое пятно > **(24) ✅ БЭКЕНД-ПАК «КОНСИСТЕНТНОСТЬ, КОТОРУЮ МОЖНО ПРЕДЪЯВИТЬ» ПРИНЯТ С ДОФИКСОМ, акт `D39.249`** (26 путей, $0). ⭐ **Приоритет №1 владельца впервые ИЗМЕРИМ по тексту, который читает человек:** два инварианта по ОТГРУЖЕННОМУ тексту с печатаемыми знаменателями, секция `BOOK CONSISTENCY` в отчёте сборки. ⛔ Первый круг приёмки дал ШЕСТЬ выживших посадок из шести — худшая оставляла прибор без провода к прогону. Порядок колонок ратифицирован и отменён в тот же день; правило и два триггера пере-открытия — ряд **406**. Каталог **169/169 RED, выживших 0** (прогон оркестратора: зону убивал потолок cgroup, 26 убийств `CONSTRAINT_MEMCG`). Ряды: закрыты 406 · 418; наполовину 407 · 417 · 419; не закрыт 408 (мотив опровергнут замером). Новые — 425–427 · 428 · 431 · 432 > **(23) ⛔ РЕШЕНИЯ ВЛАДЕЛЬЦА 11.09 РАТИФИЦИРОВАНЫ, акт `D39.248`.** Голос ВХОДИТ в приоритет №1 (проектирует Fable 5, исполняет опус — пак обязан нести пункт «обсудить с Fable») · потолок **1–2 агента Fable на сессию**, прежняя «рекомендация» ОТОЗВАНА · автономия смены с мерилом «ценности продукта → архитектура → необходимый рефакторинг → без велосипедов» · ⛔ **полигон выведен из скоупа целиком**, четыре его промта в `archive/prompts/` с баннерами. **Рабочий скоуп — платформа и бэкенд.** Прежде решения жили в рабочей записке, которая удаляется при исполнении плана. > **(22) ✅ ХОЛОДНЫЙ ПРОГОН A ПРИНЯТ БЕЗ СХОДИМОСТИ, акт `D39.247`.** ⭐ **Строка 16 закрыта замером: книга доведена от интейка до ФАЙЛА, прочитанного человеком, за $0.419424.** ⛔ Четверть денег купила пустоту (25.4 %; из них ноль знаков — 22.6 %) · пин цены flash протух на 13 % · консистентность впервые замерена по тексту читателя. Ряды **413–417**, **419**. > **(21) ✅ ПЛАТФОРМЕННЫЙ ПАК «ПРАВДА У ДВЕРИ» ПРИНЯТ С ДОФИКСОМ, акт `D39.246`,** контрактный минор **0.14.0**. `PD-455` закрыт через точку роста `Blocked.code`; `PD-162` наполовину у ОБЕИХ денежных дверей; `PD-448` разобран и НЕ построен — его четвёртый путь строит следующий пак зоны. ⛔ Приёмка нашла два дефекта вне карты автора: выживший мутант на единственной проводке `BooksDir` и тихо-зелёное в самом новом гейте. > **(20) ✅ ДИЗАЙН-ПАК «СТРУКТУРА ГЛАВ» ПРИНЯТ БЕЗ СХОДИМОСТИ, акт `D39.245`.** Глава становится ИДЕНТИЧНОСТЬЮ; `backend/docs/CHAPTER_STRUCTURE_DESIGN.md` — статус ПРЕДЛОЖЕНИЕ до пака стройки. Предметная часть устояла в четырёх кругах, механика исполнения — нет. **Пять вопросов владельцу с ценой каждого варианта — в `NEAR_TERM_PLAN.md`.** > **(19) ✅ АУДИТ БАНКА ПАМЯТИ ПРОТИВ ПРИОРИТЕТА №1, акт `D39.243`.** Ряды **406–412**; носитель разбора — `research/34`. ⭐ Главное: книжного вопроса о консистентности не задавал ни один прибор — мера построена, но считалась по ЧЕРНОВИКУ до редакторской волны. > **(18) ✅ ДОРАБОТКА ПО ИНВАРИАНТУ `D39.240` ПРИНЯТА, акт `D39.242`.** Семь предметов в двух зонах; батарея движка вернулась к входной строке, мутации **RED 151 · SURVIVED 0**, сверка 373 якорей — протухших 0. ⭐ Почти всё дорогое нашли САМИ сессии и у себя: выживший мутант вскрыл дефект в собственном пине, непримени́вшаяся собственная правка, знаменатель из восьми против моих двух. ⚠ Пять МОИХ ошибок сняты сессиями и названы в акте; куплены четыре нормы о провенансе утверждений и чисел. **Бэкендовый слот СВОБОДЕН** — следующим идёт дизайн-пак структуры глав (ок владельца получен). > **(17) ✅ ОБЕ СЕССИИ ЗАКРЫТЫ, акт `D39.241`.** Движок откачен полностью — батарея вернулась к входной строке смены (19 `ok` · 0 FAIL · 4 скипа), пере-снято моим прибором. Платформа сдала `--no-block` С ПИНОМ — единственное, что владелец взял из отменённого пака; куплен пин на ЧУЖОЕ поведение (systemd), на котором молча держалось утверждение в коде свипа. ⛔ Откат не смогла выполнить ни одна сессия, включая мою: запрет сработал одинаково, обходить не стала ни одна, дерево снял владелец. Живой журнал похудел на 19 % — закрытая хроника вынесена срезом (`7af35da`), три её одиноких утверждения получили дом строкой **402**. > **(16) ⛔ ПАК «ДВЕ ОСТАНОВКИ» ОТМЕНЁН ВЛАДЕЛЬЦЕМ до лендинга — акт `D39.240`.** Причина — размах (18 файлов движка), не риск: работа была почти целиком добавочной (+633/−84, 61 удалённая не-тестовая строка, сборка чистая). **Предмет заменён и сужен: остановка остаётся ЖЁСТКОЙ, деньги терять ДОПУСТИМО, но она обязана быть КОРРЕКТНОЙ** — без гонок, без половинчатых состояний, с верным возобновлением. Обе сессии откатывают свои зоны; знание снято с них ДО отката. ⭐ Пак оставил после себя пять нот (`D39.236`–`D39.240`) и две строки (**384**, **385**). > **(15) ⛔ ДВА SIGTERM ПОДРЯД GO-ПРОЦЕСС ВИДИТ КАК ОДИН — акт `D39.238`, замерено дважды независимо** (`gap 0` → 0 из 20, `gap 1 мс` → 20 из 20, контроль 5 из 5). Ратифицированная форма двух остановок стояла на посылке «послать два = получить два», которой нет: «останови сейчас» первым нажатием давало бы МЯГКУЮ остановку молча, а пере-выпуск жёсткого сигнала свипом — третий SIGTERM, то есть смерть без кадра и сеттла. Форма остаётся, добавлен контракт: сигналы упорядочены НАБЛЮДЕНИЕМ, факт доставки долговечен. ⭐ Первая серия замера была неверна ПРИБОРОМ и дала противоположный ответ — сессия починила прибор и назвала это сама. > **(14) ОБЕ СЕССИИ ПАКА «ДВЕ ОСТАНОВКИ» ПРИНЯЛИ РАБОТУ И ОТВЕТИЛИ ЭХО-ПРОТОКОЛОМ; шесть возражений, шесть приняты — акт `D39.236`.** Три из них — ошибки В МОИХ ПАКАХ (счётчик оценки копился бы с нуля и пин равенства был бы вакуумен · «опора готова» для строки оператору · неверный механизм следствия у блокирующего `stop`), одно — правило версий, которое я нарушил бы молча. ⭐ Все шесть пришли ПОСЛЕ двух кругов ревью: эхо-протокол оказался третьим рубежом, а не формальностью входа. > **(13) ДВА ПАРНЫХ ПРОМТА «ДВЕ ОСТАНОВКИ» ВЫДАНЫ, акт `D39.235`** — движковый и платформенный, порознь не лендятся. Форма кадра остановки ЗАФИКСИРОВАНА нотой ДО старта работ (две зоны, один шов). ⛔ Эррата к `D39.234` п.1б: мой механизм «отказ на гейте» ратифицированных ~20 минут не даёт — резервация держит всю цепочку ретраев. ⛔ Замером исполнением найдено, что платформенный `Stop` без `--no-block` блокируется на весь грейс и сломал бы `202` контракта. **Сплошной инвентарь живых доков по слову владельца: 19 мест починено**, контракт исправлен минором `0.13.1` (схема требовала отставленный член ⇒ каждый ответ `Run` был невалиден). > **(12) СЛОВО ВЛАДЕЛЬЦА ПО ОСТАНОВКАМ ПОЛУЧЕНО И РАТИФИЦИРОВАНО, акт `D39.234`:** первое нажатие — мягкая, второе — жёсткая; ждём одну летящую попытку (~20 мин), не цепочку; пак мягкой остановки и строку **377** делаем ОДНИМ заходом; коды выхода не трогаем. Пак движка ПАРНЫЙ платформенному. ⛔ Тем же актом сверены носители, которых `D39.232` не тронул: закрыты и убраны строки **78** · **331** · **360** · **369**; блокеров очереди в трекере теперь **0**. Инвентарь живых доков прогнан (94 файла): `15-money-path.md` чинен в трёх местах. > **(11) ДВА СТОПА — СЛОВО ВЛАДЕЛЬЦА НАКОНЕЦ ЗАПИСАНО, акт `D39.233`.** У человека одна кнопка, и она рвёт всё в полёте; мягкий глагол в движке построен, но дёрнуть его может только денежный потолок. ⛔ Контракт и платформа УЖЕ обещают мягкий стоп, которого нет, а платформенный грейс (600 с) меньше законного ожидания вызова (1240 с). ⛔ Пометка «это оценка» — условие слова владельца — по шву НЕ едет и потребителя не имеет (строка **382**). ✅ Замером закрыты строки **374** (вердикт главы остановка уже не портит) и **371**. Пак не заказан: ждёт слова владельца по форме (рекомендация — «повтор ужесточает», коды выхода не трогать). > **(10) ПАК «ВЫЗОВ, КОТОРЫЙ ОБОРВАЛИ МЫ» — ✅ ПРИНЯТ И ЗАЛЕНДЕН 10.09, акт `D39.232`** (`3f05fab`, 28 путей, $0). Движок перестал платить дважды за одну генерацию. Числа пере-сняты оркестратором: батарея 19 ok · 0 FAIL · 4 скипа; каталог 276 → 360, батарея 65 → 149; тесты +67 / −0; снапшот не двинулся. ⛔ Приёмка ДО ратификации нашла пять выживших мутаций, все на носителях ВИДИМОСТИ денег — то есть на условии слова владельца. ⭐ Куплены четыре нормы об измерении и три класса вырожденных пинов. Остатки — строки **375**–**377** (**374** закрыта замером, акт `D39.233` п.2). > **(9) ТРАНСПОРТ: КОНСИЛИУМ СОШЁЛСЯ, БИТ ВЛАДЕЛЬЦА ЗАКРЫТ — акт `D39.230`.** Оборванный НАМИ вызов: списывается по оценке с читателя, **пометка — УСЛОВИЕ решения**; платная проба отклонена (вопрос к вендору осознанно открыт); ожидание до ~20 мин разрешено ⇒ дедлайн от бюджета. ⛔ Попутно вскрыто: наш `research/21` §Q6 неверен ДВАЖДЫ и обе половины держали неверный дедлайн полтора месяца (эррата в его шапке); ось эскалации D2 фиктивна (строка **369**); нулевая ветвь не пишет чекпойнт ⇒ резюм ПЕРЕКУПАЕТ вызов. ⇒ **следующий движковый пак — строка 360**, пишется целиком. > **(8) ПЛАТФОРМЕННЫЙ ПАК «РАЗРЕЗ ПРИЁМА И ПРАВДА О СЕБЕ» — ✅ ПРИНЯТ И ЗАЛЕНДЕН 08.09, акт `D39.229`** (`ddcbf0c`, 26 путей, $0). Синхронный вход разреза под потолком (`x/sync/semaphore`, число из `jobs.DefaultWorkers`); граница хвоста выведена из кода; регистр приведён к правде — открытых 112 → **109**, major 3 → **1**. ⭐ Потолок сам назвал, чего НЕ ограничивает: материализатор и рекoнсайлер порождают процессы мимо него — строка **364**. Адверсариальный проход: 8 находок, 6 — дефекты этого же пака на ЗЕЛЁНОЙ батарее. > **(7) ДВИЖКОВЫЙ ПАК «ДВИЖОК УЖЕ ЗНАЕТ» — ✅ ПРИНЯТ С ДВУМЯ ДОФИКСАМИ И ЗАЛЕНДЕН 08.09, акт `D39.228`** (`2b6f1f4`, 21 путь). Закрыты строки 355 · 357 · 358; у **253** и **312** закрыта только ДВИЖКОВАЯ половина — платформенная жива и ждёт читателя (испр. 08.09 по кросс-модельному ревью ратификаций). Ратифицировано: аддитивное поле манифеста ключ НЕ двигает, но обязано быть отличимо от своего нуля. Третья смена поведения заказана приёмкой — лог и экран перестали спорить о полноте банка. Не взятое получило носители: **362** (ремонт против ремонта, 77 % денег чанка) и **363** (текстовый сайдкар молчит о неполноте). Батарея 19 ok · 0 FAIL · `EXIT=0`, каталог мутаций 259 → 276, тесты +17 / −0 — все числа пере-сняты оркестратором. > **(6) ВЫДАНЫ ДВА ПАКА 08.09, акт `D39.227`, оба $0.** Движковый «ДВИЖОК УЖЕ ЗНАЕТ» (`BACKEND_ENGINE_KNOWS_SESSION_PROMPT.md`: строки 253 · 357 · 358 · 355, попутно 312) и платформенный «РАЗРЕЗ ПРИЁМА И ПРАВДА О СЕБЕ» (`PLATFORM_INTAKE_TRUTH_SESSION_PROMPT.md`: строка 332, семь пунктов из десяти). Оба прошли опровергателя и разбор Fable 5. ⛔ **Заведена строка 360 — самый дорогой движковый класс (23–34 % цены редакторской руки), носителя у него не было;** её ДЕНЕЖНАЯ половина ждёт слова владельца (платит ли пользователь за вызов, оборванный нами) и сцеплена со строкой 331. До ответа пак по 360 не пишется. > **(4) ДИЗАЙН-ПАК 161 — ✅ НАПИСАН 07.09** (`docs/CHAPTER_STRUCTURE_DESIGN_SESSION_PROMPT.md`, `7f84c8d`), прошёл оба > рубежа. ⚠ **НЕ ВЫДАН: новый пак идёт НОВОЙ сессии, обе ночные отработали** — запуск за владельцем. > **(5) ТЕХДОЛГ БЭКЕНДА — разбор `research/33` в трекер: ✅ ЗАЛЕНДЕН 07.09, акт `D39.224`.** Заведены строки > **344–350**, дописки в 86/114/119/182/224; «переписать» не получил ни один из одиннадцати долгов. Ратифицированы > ПОРЯДОК (шаг 0 параллельно дизайну 161 → шаги 2+3 ОДНИМ окном перенарезки, wire-очередь **182** ложится в него > же → шаг 4 аддитивно) и ФОРМА запретов (жёсткие — только под ратифицированной базой, прочее — условия с > механизмом, чтобы не спорить с дизайн-паком). **Пак шага 0 ✅ ЗАЛЕНДЕН 07.09, акт `D39.225`** (две смены поведения названы, вторая денежная: прогон по арму теперь покупает банковый контур). Промт был — > `docs/BACKEND_GATES_NOT_PROSE_SESSION_PROMPT.md`, $0 и снапшот-нейтрально: строки 344 · 345 · 346(а) · 348 · 224, > попутно 349/350. Прошёл оба рубежа; вход зоны зелёный (`go test ./... -count=1` → 19 `ok`, 0 FAIL, 4 пакета без > тестов). ⚠ Единственная заказанная смена поведения — экспорт банка на стопе, и её форма ЗАДАНА аддитивной: > перенос засева в ветку стопа запрещён явно (уводит НЕПОДПИСАННЫЕ строки в глоссарий, а те инъектируются > законом ⇒ двигают `memory_version`). Снапшот-нейтральность требуется доказать байт-равенством снапшотов. > ⚠ **Пак шага 0 закрыт ТРЕМЯ дофиксами, и каждый нашёл дыру ВНУТРИ предыдущей починки** (акт `D39.225` > п.9–10): семь полей листа подписи без утверждений → `Freq` и своп списков → ранжирование и класс пустого > рендеринга. Правило остановки применено НА ТРЕТЬЕМ и объявлено сессии заранее; остаток адресован строкой > **353** и ждёт первого читателя секции (платформенная половина **224**). Оба верификатора дали явный ок на > закрытие, каждый пере-посадив свои мутации. > **(6) ТЕХДОЛГ БЭКЕНДА, ВТОРОЙ ПАК — «ПРАВДА ОПЕРАТОРУ И ДЕНЬГИ»: ✅ ЗАЛЕНДЕН 08.09, акт `D39.226`.** Закрыты строки 333–338; живое — 354–358 и остаток 353. ⚠ **Смета движка опровергнута прогоном: `tmctl manifest` есть НИЖНЯЯ граница** ($1.259217 против $0.350075, 64.6 % «купило ничего»), потолок держал машинным гейтом. Три ошибки ЗАКАЗЧИКА названы в акте п.8. Прежде: > `docs/BACKEND_OPERATOR_TRUTH_SESSION_PROMPT.md`, строки **333–338**: движок говорит оператору не то, что > делает, и платит за поверхности, которые банк уже держит. ⚠ **Первый пак смены, который тратит ДЕНЬГИ:** > холодный прогон на нескольких главах разрешён владельцем лично, потолок **$3** ставится МАШИННЫМ гейтом > движка (`ceilings.book_usd` + `--max-units`), а не обещанием сессии. Прошёл оба рубежа, и оба нашли > существенное: (1) первая редакция §4.1 заказывала фильтр, который снял бы пометки спора, которые §4.3 того > же пака просит довезти владельцу; (2) заказанное доказательство «банк тот же» ВАКУУМНО — предложение на > сид-поверхность в банк не попадает и сегодня; (3) удаление кандидатов неизбежно двигает `RequestHash` > батча, и на РЕЗЮМЕ оплаченный чекпойнт перестанет матчиться ⇒ переплата; (4) одно утверждение строки 334 > было ложным с момента её заведения — снято и в паке, и в носителе. > ⛔ **ЧТО ЖДЁТ СЛОВА ВЛАДЕЛЬЦА, поимённо:** строка **340** — сужение входа действует только на синхронной ветви, > при деплойном классе книга одним полотном попадает в библиотеку МОЛЧА, и закрыть нечем без пятой причины отказа > (`source_unreadable` терминален и УДАЛЯЕТ исходник) · строка **326** — критерия впуска в дереве нет, консьерж > против самообслуживания · обязательный ВТОРОЙ круг селф-ревью (первая половина того же слова подтверждена как > РЕКОМЕНДАЦИЯ, `D39.220`; вторая не подтверждена, улика в её пользу — ниже в этом же листе). > ⚠ **Зоны параллельны по норме проекта; ограничение — пропускная способность ПРИЁМКИ оркестратора: сериализуй > ЛЕНДИНГИ, не старты.** ⚠ Зеркало фронта — `0.2.3` против канона **`0.13.1`** (одиннадцать миноров плюс корректирующий, `D39.235` п.6), зона заморожена. > ✅ **ПОЧИНЕНО 05.09 ЛЕНДИНГОМ `616a8e4` (пак «денежный стоп», акт приёмки **D39.206**; ⚠ испр.: раньше здесь стояла D39.203 — это нота ВЛАДЕЛЬЦА про «сколько добавить», а не акт) — ниже до-паковая археология, читать как историю.** Отказ резервации больше не роняет волну: он ЗАЩЁЛКИВАЕТ её (новое не стартует, допущенное дорабатывается), а обязательный вызов ЖДЁТ settle, когда settle может помочь. ⇒ **порог «книга короче десяти глав не переводится» СНЯТ**; остаточный пол — одна резервация (~$0.07 ≈ 3 главы), и он ВЫВЕДЕН, а не замерен (замер — $0.15-прогон пятиглавой книги, передан полигону). ⚠ Разбор эрратой — `architecture/15-money-path.md`, греп `ЭРРАТА 05.09`. ⚠ **Эта строка сутки стояла непоправленной ПОСЛЕ лендинга и по ней оркестратор предупредил владельца о снятой стене как о действующей** — канон, не обновлённый лендингом, врёт громче отсутствующего. **НО КНИГУ ЧЕРЕЗ API НЕЛЬЗЯ БЫЛО ДОВЕСТИ ДО КОНЦА — найдено прогоном 04.09 и воспроизведено дважды.** Прирост потолка на прогон = `chaptersLeft × $0.03` (ставка `DefaultPerChapter`, занижена ×4.47 — D39.179 п.1), и после первой готовой главы это $0.27, тогда как движок при `waves.workers: 4` резервирует под редакторский шаг ~$0.28 ⇒ **отказ резервации, прогон встаёт, книга не двигается**. Два прогона подряд дали одно и то же: `committed` не сдвинулся, холд вернулся. ⇒ **занижение ставки — не «шкала короче», а СТОП ПРОДУКТА: с какого-то момента каждая следующая покупка не покупает ничего.** Лечить придётся согласованно двумя сторонами (ставка платформы + резерв движка под шаг с параллельными воркерами), носитель — ряд регистра зоны, вес `major` **за недостижимость продукта, а не за деньги**: сам стоп НЕ ЖЖЁТ ничего — замер платформы 04.09 показал отмену ДО ухода запроса (латентность 20–31 мс, `model_actual` пуст, токенов ноль), и вся книга сходится до микро-доллара по трём источникам (`request_log` 0.278319 · `spend.committed_usd` 0.278318752 · платформенный `committed` 278319 микро). > ⛔ **ЗАТО HALT НА ПРОГОНЕ, КОТОРЫЙ ПРОДВИНУЛСЯ, ЖЖЁТ — отдельная находка того же прогона и свежая датированная точка строки 78 («леджер = НИЖНЯЯ граница»).** Четыре редакторских вызова ушли параллельно; один дошёл ($0.063404) и своим коммитом сорвал потолок, три других отменены в тот же миг, **отработав 120756, 156469 и 156470 мс** — и легли в леджер нулём. Незаписанное ≈ **$0.05–0.19 на ОДИН halt** против $0.278 за всю книгу, то есть механизм, защищающий от перерасхода, сам создаёт неучтённый расход. ⚠ Списание провайдером НЕ доказано (биллинга у нас нет) — утверждается ровно наблюдаемое: вызовы шли 2–2.6 минуты, их цены в леджере нет. > ⇒ **Дыра НЕ в принципе, а в покрытии, и это делает её заказом, а не наблюдением** (разбор оркестратора 04.09 по коду): консервативная оценка уже построена и ратифицирована — `backend/internal/pipeline/stagerun.go`, греп `settling the reservation estimate to keep the ceiling honest` (pack-13 point-9), — но её условие требует ОТВЕТА провайдера (`resp.Usage`), а отменённый в полёте вызов ответа не получает и уходит другим путём. Направление лечения: сеттлить оценку при отмене вызова, который успел уйти; различитель — факт ухода (латентность кандидат, порог обязан быть обоснован замером, а не назначен). Половина ДВИЖКОВАЯ. ⚠ Прежняя формулировка пункта — ниже, она о состоянии ДО 04.09. Движок пишет файл с 30.08 (`tmctl build` — EPUB 3 + чистый txt, D39.175), и холодный прогон 31.08 предъявил это живьём: собранный EPUB настоящего перевода прошёл `epubcheck` 0/0/0/0 и передан владельцу. ⚠ **ЭТОТ АБЗАЦ ЗАКРЫТ 04.09 и оставлен как история:** дверь выдачи ПОСТРОЕНА и заленджена (`adf5e53`, D39.194), смонтировано **18 операций из 21** (три адреса двери: `createExport`/`getExport`/`downloadExport`), долг `П-17` зона пере-сняла. Прежняя проверка «`grep -rn 'createExport\|getExport' platform/internal/` — пусто» БОЛЬШЕ НЕ ПУСТА и как гейт не работает. Не смонтированы по-прежнему `getRun`, `updateBook`, `deleteBook` — `updateBook` несёт продуктовое следствие, строка бэклога 274 (имя книги в выданном файле не чинится ничем). **Слово «отдаёт результат» ложно по букве ТОЛЬКО платформенной половиной** (п.4) · **(2) ~~холодный прогон движка~~ ОТРАБОТАЛ 31.08, закрыт РЕШЕНИЕМ ВЛАДЕЛЬЦА «не доводить»** (отчёт — `archive/reports/COLDRUN_V16_REPORT_2026-08-31.md`, числа относятся к `065d8ac`). Потрачено **$0.436110** из санкции $0.80. ПРЕДЪЯВЛЕНО живьём: объёмный потолок · D39.158 ОБЕИМИ половинами (стоп и не-стоп) · exit 16 · строки 154/198/239/240. ⚠ ~~**Причина большой доли редактора НЕ УСТАНОВЛЕНА**~~ — **УСТАНОВЛЕНА пробой полигона 02.09 по четырём осям: РЕДАКТОР ДУМАЕТ, А НЕ ПИШЕТ.** Размышление — **77.9%** цены редактора без ручки и 45.7% с `low`; у `glm-5` с выключенным thinking — 0.0%. Замер куплен и закончен ($6.17 из $9.50). ⚠ `research/30` §2.4 того же полигона повторяет «причина не установлена» — это про ДРУГОЙ вопрос (доля роли в прогоне против доли размышления в цене роли), и различение обязано попасть в ревью-шапку 30. Доля редактора идёт с ДВУМЯ знаменателями: **49.3%** от всего прогона ($0.214865 из $0.436110) и **81.3%** внутри порции П1 (⚠ ходившее «73%» — фантом, в отчёте его нет ни разу). Следующий шаг — контролируемая проба по ЧЕТЫРЁМ осям (роли осей и три требования, купленные ошибками этого прогона, — §14 отчёта; ось `stale` НЕДОСТИЖИМА — §10 там же). ⚠ **Цена: слово владельца 31.08 — ≈$0.60, потолок $0.80, ДЕСЯТЬ глав ПОЛНОЙ цепью включая редакторскую волну.** ⚠ **КЛЮЧИ: гейт снят словом владельца 30.08, разбор двух путей — D39.176 п.6.** Живое отсюда: конвенционного `.env` НЕТ НИ У ОДНОЙ книги корпуса (заполнены только `projects/textmachine/backend/.env` и `.../eval/.env`), поэтому прогон движка обязан передавать `--keys-file` абсолютным путём и только на `translate`; для п.3 нужен ДРУГОЙ файл — `TM_PLATFORM_ENGINE_KEYS_PATH`, тоже АБСОЛЮТНЫМ путём (`platform/internal/config/config.go`, греп `must be an absolute path`). Лечение операционное и $0 — направить переменную на уже заполненный файл; проверять ПРОГОНОМ, не чтением (гардрейл `.env`) · **(3) живой сквозной прогон через API платформы** — форма манифеста, сайдкара банка и карта причин флагов сочинены платформой САМОСТОЯТЕЛЬНО. ⚠ Уточнено 01.09: гейт СНЯТ холодным прогоном, и настоящие артефакты движка теперь ЕСТЬ (каталог `books/gu-zhenren/coldrun-v16/`), но сверка вышла ТОНКОЙ: на шов реально вышло **одно значение `flag_reason` из пятнадцати** (`sanitizer_stripped`), остальные четырнадцать по-прежнему только чтением кода, а манифест против `platform/internal/ingest/manifest.go` не сверялся вовсе · **(4) дверь выдачи** — строго ПОСЛЕ (3) (⚠ слово владельца 30.08: дверь ВСЕГДА строит файл — отказ юзеру не отдаётся, неполная книга уходит с пометкой, т.е. дверь зовёт `tmctl build --partial`; отказ по умолчанию остаётся операторской ручкой CLI; D29.1(б) «fail-closed» читать как «никогда молча» — честность несут пометки) · **(5) проводка `--max-units`** — снятие гейта, а не стройка: механизм в движке стоит (D39.170), живое основание гейта — `PD-422` · **(6) разморозка фронта** — ПОСЛЕ (4): зеркало отстало на **ВОСЕМЬ** миноров (`frontend/docs/api-contract/openapi.yaml` — `0.2.3` против канона `0.10.0`, и первый из них — ЛОМАЮЩИЙ 0.3.0), **16 операций против 21**; зеркало последний раз двигали 15.08 — ⚠ ходившее «30.08» было взято из текста коммита, а не из `git log` (испр. 05.09), то есть расхождение старше на две недели; отставание ратифицировано D39.142 п.5 на время фриза и две ручки разъехались, размораживать раньше значит перегенерировать типы дважды. ⚠ **ДВА ЗАГЕЙЧЕННЫХ ТРИГГЕРА НАЖАТЫ И НЕ ОТРАБОТАНЫ — строка бэклога 237** (`go.work` · вендор-сверка эффорта `deepseek-v4-pro`; реестр `13-tech-debt-anchors.md` §Б-108). ⚠ **Состояние git — снимать КОМАНДАМИ, не чтением** (ветка `polygon` ушла вперёд, коммит здесь не цитирую): работа полигона лежит на ней и в `main` НЕ влита, а `git status -- eval/` в main-дереве пуст ПО ПОСТРОЕНИЮ и уводит в ложный вывод «работы нет»; ⚠ **«развязка git с origin» — арбитр ПЕРЕ-СНЯТ 04.09 и прежний вердикт БОЛЬШЕ НЕ ВЕРЕН:** `git merge-base --is-ancestor origin/main main` → **rc 1**, `git log main..origin/main` → `afa7700 temp` (коммит владельца 04.09, которым он передавал работу зон). Локальная линия ушла вперёд на семнадцать коммитов и содержит ВСЁ содержимое `afa7700` — оно снято `reset --soft` и заленджено раздельными зонными коммитами, — но формально ветки разошлись. Лечение — force-push рукой владельца; **не пуллить** (его же правило). ⚠ Пункт «развязка git с origin» в листе владельца ниже держится ТОЛЬКО как вопрос про force-push его рукой; утверждением о расхождении дерева он не является — арбитр этой пары именно здесь. > - ⚠ **Норма приёмки, купленная аудитом D39.167 п.1:** акт лендинга, объявивший закрытие строки регистра или бэклога, обязан быть СВЕРЕН СТАТУСОМ в тот же заход — иначе следующий пак собирается ПО РЕГИСТРУ и едет чинить построенное. Машинная половина — строка бэклога **225**. > - ⚠ **ЛЕНТА КОНТРАКТНЫХ МИНОРОВ** (что принёс каждый — телом ноты): **0.5.0** — D39.161 · **0.6.0** — D39.162/D39.163 · **0.7.0** — D39.166 · **0.8.0** — D39.169 · **0.9.0** — D39.180 · **0.10.0** — D39.194 (дверь выдачи: `downloadExport`, `failure_code` словарём, `Export.url` относительный; ⚠ читать с эрратой 04.09-в — минор был ратифицирован без своей кодовой половины и сутки жил ложным на проводе). Прожитые дампы приёмок P9/P10 — `archive/PROGRESS-2026-08-backend.md` и тела нот. > - **ЖИВОЕ:** полигон — **фаза Д ИДЁТ** (заказ 10.08; деньги санкционированы 15.08 напрямую полигону — ⚠ числа потолка в носителях расходятся, фактическую цепь сверить при лендинге петель; ja-книга `enkan_no_hate_ja`; при ратификации фазы Д в D-ноту: декой-правило + обязательный кросс-семейный опровергатель приёмки — одобрены 10.08; свежие фриз-коммиты полигона в дереве — НЕ трогать) · платформа и контракт — статус в строке выше, здесь НЕ дублируется (один носитель на факт) · **фронт ЗАМОРОЖЕН** (D39.136 п.2 + **D39.147: морозится ДАЛЬШЕ лендинга P7 — слово владельца 17.08; P7 зону НЕ размораживает, S5-промт не выдаётся, разморозка отдельным словом по достижении сквозного пути**; перечень первого касания зоны — синк зеркала на ТЕКУЩИЙ канон (отставание и его цена — п.6 очереди выше и строка бэклога 183(б)) + перегенерация типов + моки + гейт утечки конвейера + ФС-1..12 + Ф-63/Ф-28 + фразы В-11 по словарю кодов — не отменён, ждёт разморозки) · закрытые стройки эры — реестром нот `architecture/05-decisions-index.md` (D39.130–137, одна строка на ноту). > - **Открыто на владельце:** ⚠ **НОВОЕ 06.09: второй круг селф-ревью** — бэкенд-сессия передала слово владельца «после сдачи обязателен селф-ревью, и если он дал исправления — НОВЫЙ круг, проверяющий исполнением и исходный заказ, и закрытие находок предыдущего круга». Первую половину того же слова (комментарии) он подтвердил как РЕКОМЕНДАЦИЮ, про вторую не сказал ничего; в мандате самопроверки `CLAUDE.md` сегодня описан ОДИН круг. Сессии исполняют добровольно, каноном не стало. ⭐ **УЛИКА В ПОЛЬЗУ ПРАВИЛА, снятая в ту же ночь 07.09:** круг 2 бэкенд-сессии опроверг ЕЁ ЖЕ правку круга 1 — свёртка сравнения через `NormalizeSourceKey` вводила ЛОЖНООТРИЦАНИЕ (замер зоны: `ReplaceGlossary(族長 + 族长)` → `rows stored=2`, контроль на байт-равном `src` → `UNIQUE constraint failed`, то есть UNIQUE стоит на СЫРОМ `src` и обе строки инжектятся), и мутация «свернуть сравнение» до круга 2 ПЕРЕЖИВАЛА весь пакет. Один круг сдал бы тихо-зелёное. · ✅ **Развилка строки 291 ЗАКРЫТА владельцем 05.09 — `D39.204`:** отказ резервации на ретрае деградирует во ФЛАГ («пусть флагает просто как-то»); вариант «минимальная покупка ≥ `step_max_usd`» снят. ⚠ Это оказалось НЕ сменой канона: D2 уже кончается флагом, денежная ветка до него не доходит. · ✅ **Лестница D25.1 ЗАКРЫТА владельцем 05.09 — `D39.205`:** копия БЕЗ пометки = книга БЕЗ ЕДИНОГО ПРОПУСКА; любой пропуск ⇒ пометка в файле, гранулярность — ЮНИТ (пропущенный кусок главы критичен). Имя файла решено паком `7e2226a` (вычисляется при скачивании). ⚠ Прежняя редакция держала это открытым на владельце — по ней он и получил вопрос, который сам уже закрыл · лейбл главы без заголовка (сейчас цифры; словесный шаблон = одна строка `reader.txt` после ратификации К-3) (⚠ три вопроса пака ЗАКРЫТЫ словом владельца 30.08: экспорт юзеру — всегда строить, см. п.4 очереди · модель пометок подтверждена как построена — надпись о пропуске в файле, отдельный варнинг-слой в интерфейсе НЕ строим, машинный отчёт сборки остаётся внутренним носителем (дрейф) · RTL — снят до появления право-налевой целевой пары) · ⚠ **ПЛАТФОРМЕННЫЙ ЛИСТ ЗАКРЫТ СЛОВОМ ВЛАДЕЛЬЦА 30.08 — четыре ответа и их следствия ЦЕЛИКОМ телом D39.176** (квот нет · продажа не в бете · продолжение после пополнения — руками · фразы пользователя делегированы проекту с требованием интернациональности). ⚠ **Лист ПУСТ:** последний его пункт (`PD-421`, «держит ли открытый поток сессию живой») СНЯТ замером 30.08 — окно бездействия сессии **14 суток**, абсолютный срок **30** (`platform/internal/config/config.go:346`=`defaultSessionIdle`), скольжение окна идёт на любом аутентифицированном запросе, а поток теряется лишь после того, как подметён протухший ряд, то есть после ДВУХ НЕДЕЛЬ без единого действия пользователя. ⚠ Часовой интервал в этой теме — периодичность УБОРКИ, а не срок сессии (эррата 30.08-а к D39.176 п.5) · ⚠ Гейт словаря фраз — строка **204** (D39.176 п.4). ⚠ Прежний указатель «строка 148» мёртв — строку удалил `a023e39` решением владельца, восстанавливать Приложение А по ней НЕ надо · **развязка git с origin** (локальная линия ИСТИННА, force-push его рукой; не пуллить) · В-4/Ф-30 (глава без заголовка — движковая половина строка 160) · мини-проба флора 44 (одобрена, промт не выдан; число — после ре-пробы 188) · ~~подпись денежного шага 46~~ (ратифицирована D39.190 п.4: пере-снапшот батча — единым актом, цена сегодня $0) · **схема time-based DeepSeek** — рекомендация и её доводы строкой **172**(а) · **вход ратификации фазы Д:** посылка «dspro дешевле glm» в пике ПЕРЕВЁРНУТА (×1.26 дороже, D39.137 п.4) · **возражение Sol по проходу `tier` эксп-23** (довод дословно — слайс `archive/PROGRESS-2026-08-10-15.md`: Sol судил СВОЁ семейство, что запрещено D13.3; подтвердить или снять — при лендинге петель фазы Д) · фронт-вопросы зонного журнала: В-7 (плотность; держит Ф-54) · В-8 (слово состояния в дереве) · В-9 (языки интерфейса — механизм готов, ПТ-36) · Ф-38 (вкладка «Замечания»). Закрытые пункты листа — в нотах D39.136–145, здесь не держатся. > - **Сделано (сводно)** — снимок ленты закрытых эр в [archive/PROGRESS-2026-08-04-09.md](archive/PROGRESS-2026-08-04-09.md); детали — D-лог и слайсы. > - ⭐ **КУРС НА 04.09 — ПОРЯДОК РАБОТ, СОБРАННЫЙ ВЕЕРОМ ПО ВСЕМУ БЭКЛОГУ (31 агент, 46 кандидатов, шесть срезов + опровергатели + критик полноты).** ⚠ Главный результат метода, а не списка: **из 46 кандидатов бэклога опровержение пережили ДВА** — остальное трекерная инерция; а то, чего в трекере не было ВОВСЕ, оказалось тяжелее всего, что в нём есть (строки **269–275**, заведены этим же заходом). Порядок: > **(1) ЭКСПЛУАТАЦИЯ — ✅ ЗАКРЫТА ЛЕНДИНГОМ 05.09 (`7e2226a` + `3e84716`, акт D39.201): бэкапы с ПРЕДЪЯВЛЕННЫМ восстановлением, дверь для не-браузерного клиента, имя книги. Строки 269 · 270 · 274 закрыты и сняты из таблицы; ниже — история заказа.** Строка **269** бэкапов нет ни у оплаченной работы, ни у денежного реестра — ЕДИНСТВЕННАЯ находка дня без частичного исхода: одна потеря диска необратима и недоказуема · строка **270** у продукта НОЛЬ дверей: `bearerToken` объявлен и не выдаётся, живой цикл 04.09 прошёл через dev-вход, который прод отказывается запускать, фронт заморожен · строка **274** имя книги в выданном файле исходноязычное и не чинится ничем (дёшево, а ломается первое, что видит человек). > **(2) ДЕНЬГИ И ЕДИНИЦА ЗАКАЗА — РЕШЕНО 04.09 во ВТОРОЙ редакции, строки 276–283: заказ это ОБЪЁМ, объём меряется ЗНАКАМИ ИСХОДНИКА ПО ЮНИТУ (движок публикует в манифесте), «страница» — их отображение и её размер это ДАННЫЕ ЛОКАЛИ; вердикт ДО клика, сумму человек не выбирает.** ⚠ Первая редакция мерила ГЛАВАМИ и пала: глава надёжна в одном случае из трёх, дыру нашёл владелец. ⚠ Тем же вопросом вскрыта ВТОРАЯ ненадёжная единица — `character_count` считает байты файла (для EPUB — zip) и подписан у пользователя «Знаков», строка 282. ⚠ **ФОРМА ЗАКРЫТА РЕШЕНИЕМ ВЛАДЕЛЬЦА 05.09 (D39.196): баланс — ДЕНЬГАМИ и виден, ползунок потолка — деньгами, второй ползунок объёмом (главы если распозналось, знаки если нет), старт = холд.** Запрет «денег в UI» ОТОЗВАН владельцем; ждать от него больше нечего. Разбор трёх независимых чтений в `architecture/15-money-path.md` §«ОТКРЫТАЯ РАЗВИЛКА 04.09»; `PD-440`/`PD-441`. Смена единицы — амендмент **D39.84**, объявленный требующим отдельного слова ещё при вписании глав (D39.110 п.2а, «добор оркестратора»); сам владелец 28.08 назвал нынешнюю ручку «денежной ручкой с подписью главы» (**D39.165 §1**). ⚠ Смена единицы БЕЗ «сказать, когда кончилось» ухудшает продукт: стена перестаёт быть свойством книги и становится свойством ввода, то есть встречается ПЕРВЫМ действием, а не в конце. > **(3) ДЫРА ЧЕРЕЗ ПОЛЬЗОВАТЕЛЬСКУЮ ДВЕРЬ — ✅ ЗАКРЫТА ЛЕНДИНГОМ 05.09 (`81a89e9`, акт D39.206): граница `internal/membank/wirefence.go`, три точки исполнения, инвариант снова выполняется КОНСТРУКЦИЕЙ. Строка 271 закрыта и снята; ниже — история заказа.** Строка **271**: правки банка едут в system-сообщение дословно, а ратифицированный инвариант «untrusted DATA, никогда инструкции… выполняется КОНСТРУКЦИЕЙ» конструкцией больше не выполняется. Дёшево, и обязано быть закрыто ДО первого внешнего пользователя. > **(4) КАЧЕСТВО — ЦЕЛЬ №1. ⚠ ФОРМУЛИРОВКА «НЕ МОЖЕТ СТАРТОВАТЬ» БЫЛА НЕВЕРНА И СНЯТА ВЛАДЕЛЬЦЕМ (D39.198 п.5, испр. 05.09):** из четырёх названных гейтов (24 · 13а · 55 · 149) ТРИ сняты его словом, четвёртый гейтом не был. Живое здесь другое и оно в строке **275**: приоритет назван — **(1) 100% консистентность · (2) отсутствие выдумок · (3) художественность**, и он говорит не о весах рубрики, а о том, ЧЕЙ ОТКАЗ ОСТАНАВЛИВАЕТ ВЫПУСК. Классы дефектов привязываются к УЗЛАМ (банк · редактор · черновик), а не сливаются в одно взвешенное число: оно не диагностирует. ⚠ Дорогое расхождение здесь остаётся, но НЕ то: приоритет №1 сегодня кодом НЕ исполняется — доки держат порог 98%, `glossary_miss` отгружается флагом ранга 5, а приоритет №2 носителя не имеет вовсе (строка **286**). > **(5) ВТОРАЯ ПАРА ЛОМАЕТСЯ МОЛЧА — после (1)–(4), пока пара одна, цена ошибки нулевая.** Строка **272** шаблон книги один на все пары и раздаёт КАЖДОЙ книге `transcription: palladius` · строка **273** пар-шов асимметричен: нет промптов — падает громко, нет целевых ДАННЫХ — выключается молча ВМЕСТЕ С БАНКОМ, то есть книга переводится целиком за полные деньги без механизма консистентности · строки **258**/**259** через раннер нет ни одной фикстуры с не-ru целью, латинописьменной цели в репо нет вовсе. > ⚠ **Что веер НЕ менял:** горизонт (ДОБОР ИДЕАЛА → вторая пара → МАСШТАБ → пилот → ридер-IDE) остаётся тем же; переставлен ПОРЯДОК ВХОДА в него, и вход теперь эксплуатационный, а не качественный — потому что пускать пользователя некуда и нечем страховать. > - **Курс:** этапы ОБЩНОСТЬ · КАЧЕСТВО БАНКА · ПАКЕТ-ЧЕКЕРОВ · ФРОНТ-ЭРА · шов/платформа/движковые блокеры — ПРОЙДЕНЫ (D39.59–123). Хвосты курса живут строками: 16 (полная цена холодного старта; edit-волна на малых прогонах отработала и оплачена — 58 вызовов волновым драйвером 23–25.07 плюс 648 до драйвера, счёт по леджерам `~/books/gu-zhenren/**/*.db`) · coldrun-b фаза C заморожена чекпойнтом легитимно (D39.86; эталон денег/поведения — coldrun-a, read-only); развилка 0731 решена и исполнена (D39.87/91, код `553f1a3`). > - **Горизонт (D39.62/67, освежён D39.95):** **ДОБОР ИДЕАЛА** (первым прогоном: оси голоса 24 · авто-режим · цена 16; остаток арбитража банка = рецензент спорных кластеров при ре-пробе — D39.102). ⚠ **Испр. 05.09 (D39.198 п.5):** прежняя редакция держала здесь ТРИ предусловия, снятых владельцем, — жильцы ролей (149: разморозка ничего не разблокирует, пока идут доработки) · веса K1–K12 (13а: веса не нужны, мерить по узлам) · вне-претрейн чекпоинт (55: прогоняем на тех же текстах, оговорка — ограничение ВЫВОДА, а не требование новой книги) → ВТОРАЯ ПАРА живьём (ja→ru; преп 81) → МАСШТАБ → пилот Ф2.5 (гейт резюме-строки 80; строки 62–68, 85) → Ф3 ридер-IDE (69–71). **Стоячие:** ToS-триггер 25.10 · Ш-2 до go1.27 (⚠ + x/text Unicode 17 тем же тулчейном — строка 119, реестр §Б-108 справочника якорей) · платные прогоны разблокированы (проба провода — D39.97, конфиги 112 залендены). > - **Стек (полная карта роль→модель→конфиг→квирки — [STACK.md](STACK.md), D39.126):** draft deepseek-v4-flash thinking-ON `low` **⚠0731** → терминолог (та же модель) → editor deepseek-v4-pro БИЛИНГВ ИНТЕРИМ (топология ПОДТВЕРЖДЕНА при неразличимости жильцов — D39.117; закон-блок ОБЯЗАТЕЛЕН и ВНЕСЁН — D39.104 п.2, вайр-батч принят D39.199; glm-5 резерв; вахта маппинга эффорта pro — §Б-108) → судья gemini (Ф2, в движке НЕ построен — строка 33); канал B Mistral+grok; ~$0.85/ранобэ (D30.4) — ⚠ **ТРИГГЕР ПЕРЕ-КАЛИБРОВКИ СРАБОТАЛ 31.08** (испр. 02.09): платный прогон отработал и дал собственную оценку движка `projected_book_usd = 1.1377277707` на десяти главах при куплённых $0.436110; число D30.4 держать как июльское. ⚠ **Вендор-факты 13–15.08 (пере-пин ИСПОЛНЕН и ПРИНЯТ, D39.137):** таблица цен запинена ПИКОМ (flash 0.44/1.32 · pro 1.32/3.96/кэш-хит 0.044 за 1M; счёт шиппинг-c1 = 100% DeepSeek ⇒ ×4.2–4.4 в пике / ×2.1–2.2 в долине — замер по трём прогонам); ⚠ **испр. 05.09: носители про эффорт `pro` БОЛЬШЕ НЕ ПРОТИВОРЕЧАТ** — и квирки (§3г), и `STACK.md` говорят одно: ручка ДОХОДИТ до модели с вендор-апдейта 13.08. Живой остаток один — вендор-сверка маппинга и ВЕЛИЧИНА эффекта, строка **237**(б); ⚠ ВЕСА pro сменились под тем же слагом (V4-Pro-0813, класс D39.61) — вахта-риг готов (остаток 172); покупки фазы Д на deepseek до 16.08 16:00 UTC — по старым ценам. ⚠ **ВЕСЬ банковый контур (банкнота+терминолог+классификатор) ВКЛЮЧЁН в shipping-c1 с `b8154cd`** — `enabled: true` у обоих гейтов и `classify_types: true`, бюджеты по $1.00 (прежде жил только ран-локальным конфигом книги; строка 140 — ⛔ его единственный вход `mining.contrast_path` в git ОТСУТСТВУЕТ, развёртывание обязано положить артефакт, иначе контур не исполняется вовсе, носитель — строка 251; сверка STACK.md 09.08 — факт шире прежней декларации «одна банкнота»); эскалация в shipping за `budget_usd: 0` (STACK.md §примечания). > - **ЕДИНЫЙ БЭКЛОГ — отдельный файл [BACKLOG.md](BACKLOG.md)** (одна таблица, единственный трекер проекта, ID строк прежние; каждая петля обязана иметь диспозицию: решено / отложено-с-записью / отклонено; ведёт оркестратор). ⚠ **Счёт очереди — бюллетень в ШАПКЕ ТОГО ФАЙЛА, здесь копии НЕТ** (`python3 docs/scripts/counts.py`; переезд 06.09 — D39.218). > - Архивы хроники: `archive/PROGRESS-2026-07-04-10.md` (D31) · `-10-13` (D39.6-гигиена) · `-13-25` (стройка паков 11–16, rerun2) · **`-25-31` (паки 17–20 · мини-прогон · полигон-пакеты 5–8 · ToS · холодный прогон; D39.26–58)** · **`-08-01-02` (сессии №9/№10: общность · качество банка · coldrun-b · открытие фронта/платформы; D39.59–90, срез D39.105)** · **`-08-02-04` (сессии №11–№13: ручки эффорта · стандарты · контракт API · платформа P0 · банк-арбитраж; D39.91–105 + снимок шапки эры №15)** · `-08-04-09` (пинги закрытых паков эры №15) · **`-08-14-15` (закрытые бэкенд-записи №16–17: эмиттер шва · migrate · пере-пин DeepSeek; вынесено D39.139)**. Записи ниже — живой хвост (№16+, эра D39.124+; подрезка D39.139). ## 📌 СОСТОЯНИЕ ПАКОВ **Залендены и ратифицированы, приёмочные дампы — телами нот:** платформенный **P11** — D39.169 · движковый пак **«деньги»** — D39.170 · платформенный **P12** — D39.180 (вместе с контрактным минором **0.9.0**; `PD-425` закрыт им же) · бэкенд-пак **«деньги и честность выдачи»** — D39.182 (тестов 1045→1083, удалённых ноль) · **закон раскрытия** движка — D39.181, ратифицирован владельцем и применён к одиннадцати экземплярам. ✅ **ПАКИ 05.09 ОТРАБОТАНЫ И ПРИНЯТЫ ОБА С ДОФИКСОМ, промты в `archive/prompts/` с баннерами исхода, зоны свободны:** движковый «денежный стоп» — `81a89e9` + `616a8e4`, акт **D39.206** (18 находок приёмки, 6 снято, 12 устояло, 4 major — все четыре оказались УТВЕРЖДЕНИЯМИ, а не поведением); платформенный «пустить внутрь можно» — `7e2226a` + `3e84716`, акт **D39.201** (20 находок, 5 снято, 15 устояло, 5 major — ТРИ в самом механизме бэкапа). Ниже — история паков 04.09. **ПАКИ 04.09 ОТРАБОТАНЫ И ПРИНЯТЫ ОБА (испр. 05.09).** Платформенный «закрыть цикл» — `adf5e53`, **D39.194**, контрактный минор 0.10.0 тем же актом (⚠ эррата 04.09-в: минор ратифицирован БЕЗ своей кодовой половины и сутки жил ложным на проводе; починено `7e204db`). Движковый вайр-батч — приёмочный коммит **`74ffe4f`**, **D39.199**, принят С ДОФИКСОМ; строки заказа 210·113·46·134·140·184·232 ЗАКРЫТЫ и сняты из таблицы, найденное вне карты отчёта заведено строками 287–290. ⚠ Эррата 04.09-д («пак НЕ принят») ИСЧЕРПАНА этим актом. **ПАКИ 05.09 ВЫДАНЫ И ИДУТ:** движковый **«денежный стоп перестаёт быть аварией»** (`archive/prompts/BACKEND_MONEYSTOP_SESSION_PROMPT_2026-09-05.md` — строки 271 · 277 · 278 · защёлка отказа) и платформенный **«пустить внутрь можно»** (`archive/prompts/PLATFORM_OPERATIONS_SESSION_PROMPT_2026-09-05.md` — строки 269 бэкапы с предъявленным восстановлением · 270 дверь для не-браузерного клиента · 274 `updateBook` · рантбук деплоя). **ПАКИ 04.09 РАБОТАЛИ ПАРАЛЛЕЛЬНО** (зоны независимы по коду; сцеплений ДВА, и второе найдено 04.09 уже после выдачи промтов — оба про то, чтобы не сорвать платный прогон платформы: > **(1) форма манифеста ЗАМОРОЖЕНА на окно** (`D39.190` п.5): гейт интейка — строгое равенство одной константе, бамп отправил бы каждую книгу в `parser_unavailable`. > **(2) ⚠ ДАННЫЕ ЯЗЫКОВОГО ПАКЕТА — ТОЖЕ.** Правка `backend/internal/lang/data/*.txt` двигает `EmbeddedVersion` → `cutTag` (докстринг `backend/internal/pipeline/manifest.go`: «the embedded data feeds the CJK numerals and sentence terminators that place boundaries») → ключ валидности манифеста → на платформе `recut := storedKey != in.ManifestKey` (`platform/internal/pgstore/readmodel.go`) → `delete from unit_resolutions where book_id`. То есть у книги, за которую заплачено, исчезают замечания читателя и счётчики глав — это строка бэклога **198**. ⇒ **Лендинг правки данных не кладётся, пока книга платного прогона живая**; порядок лендинга — обязанность оркестратора, зоны об этом предупреждены пингами 04.09. Рычаг у бэкенда есть и он объявлен предпочтительным: снять рендер в Go, данные не трогать): бэкенд — вайр-батч `docs/BACKEND_WIREBATCH_SESSION_PROMPT.md`; платформа — «закрыть цикл» `docs/PLATFORM_EXPORT_SESSION_PROMPT.md`. ⚠ Строка **160** взята, но идёт СВОИМ паком ПОСЛЕ двери: она бампает `manifestVersion`, у которого безопасного порядка деплоя нет (`D39.190` п.2). Строка **142** — после шагов 0–1 полигона (`D39.190` п.3). > **Предыдущие паки ОТРАБОТАНЫ 03.09, ПРИНЯТЫ С ДОФИКСОМ и заленджены** — `D39.187` движок, `D39.188` платформа; составы и приёмочные дампы ТЕЛАМИ НОТ, промты в `archive/prompts/` с баннерами исхода, план паков — `archive/reports/NEXT_PACKS_PLAN_2026-09-03.md`, решения — D39.190. ⚠ Живое отсюда одно и оно уже вылечено паком P13: **у формы манифеста БЕЗОПАСНОГО ПОРЯДКА ДЕПЛОЯ НЕТ** — гейт интейка сравнивает версию со строгим равенством одной константе (`platform/internal/ingest/manifest.go`, греп `KnownManifestVersion`), окна двух версий нет, поэтому порядок «сначала платформа, потом движок» из рантбука разворачивается на обратный. ✅ **СНЯТО ЛЕНДИНГОМ 06.09 (`D39.208`): гейта БОЛЬШЕ НЕТ.** Флаг едет в argv на КАЖДОМ спавне и пересчитывается, а названное ниже «живое основание» вылечено расширением условия — `--resnapshot` теперь едет на ЛЮБОМ продолжении, не только после правки банка (`PD-422`). Ниже — прежняя редакция, историей: ⛔ **Проводка `--max-units` в платформу остаётся ГЕЙЧЕНОЙ. Живое основание одно и оно механическое:** единственный писатель `bank_moved_at` — дверь правок банка (`platform/internal/runs/bank.go:211`=`one statement sets it`), а рост АВТО-банка от майнинга этого флага не ставит, поэтому майнящая книга на второй покупке идёт без `--resnapshot` и умирает на снапшот-гарде движка — холд взят, попытка сожжена (`PD-422`). ⚠ **Сюда же переехал остаток закрытой строки 234 (испр. 05.09): проводка полей `rebill_*` через шов — часть ЭТОГО гейта, а не отдельная работа**; ревизия справедливо заметила, что после закрытия 234 её остаток остался без видимого носителя. Это чинится проводкой признака движения банка от майнинга, а не решением владельца. **ОТКРЫТО НА ОРКЕСТРАТОРЕ №22:** ~~**Ресёрч-сессия `textmachine-36`** — лендинг `research/29`~~ **ЗАКРЫТО 04.09.** Оба отчёта топологии заленджены полигоном на СВОЕЙ ветке по прямому указанию владельца (`a7951a7`) и приехали в `main` мержем ветки — то есть маршрутом, который и был назван правильным. Файлы на месте: `docs/archive/research/29-harness-topology-survey.md` и `…-codex.md`. > ⚠ **ЖИВОЙ ОСТАТОК — РЕВЬЮ-ШАПКИ, и он на оркестраторе.** ✅ **У `research/30` шапка НАПИСАНА 05.09 — долг по нему закрыт** (попутно исполнена эррата, которую он сам требовал пять недель: `research/22` «LinguaGacha явно НЕ в мульти-агент/редактор» помечено протухшим; и снято его же требование к `29-codex` — якорь `:368` протух, реальный носитель `:108` говорит слабее и о другом). ✅ **У `29-codex` шапка НАПИСАНА 05.09** — и она подтвердила снятое выше независимо: его же §4 п.12 говорит, что пробел в long-form детекторе машинности — в held-out точности и доле ложных срабатываний, **а не в русском языке**. ✅ **У `research/29` шапка НАПИСАНА 05.09 — ДОЛГ ЗАКРЫТ ПО ВСЕМ ТРЁМ ОТЧЁТАМ.** ⛔ Первым в ней стоит §5.6: **сфабрикованный sha256** (совпали 52 знака из 64, хвост дописан по памяти, потому что хеш ни разу не был виден целиком из-за `cut` в конвейере) — и норма, из него следующая: идентификатор, не виденный ЦЕЛИКОМ в выводе команды, нельзя воспроизводить по памяти. Тот же класс, что `D39.207` п.5, пришедший с другой стороны. ⚠ И граница, которую обязан знать всякий, кто цитирует оттуда числа: из 113 находок автор лично пере-открыла ШЕСТЬ. ⚠ Расхождения `29` и `29-codex` между собой НЕ разрешены никем — автор `29` не читала параллельный отчёт дальше его §1, (⚠ испр. 05.09: сама шапка 29 уже поправлена — «НЕ закоммичено» помечено протухшим, файл в `main` с `a7951a7`; здесь остаётся долг ШАПКИ, а не факта о коммите). До шапок читать оба отчёта как ФАКТУРУ, не как ратифицированное. ⚠ Формулировка, которую шапка обязана нести, иначе следующая сессия выбросит замеры топологии: **судья как СТАДИЯ ДВИЖКА не построен и не вызывался (0 вызовов), но судьи в ПОЛИГОНЕ были и есть.** ⛔ **Маршрут закрыт словом владельца 02.09: «не трогай соседнюю git tree ветку вообще»** — файл принадлежит ветке `polygon`, в `main` приезжает мержем ветки, копированием из соседнего worktree — никогда (№22 так сделал, был поправлен, лендинг откачен). **НОРМЫ, ЗАРАБОТАННЫЕ ЭТИМИ ПРИЁМКАМИ:** - **Зелёная батарея — это ПОЛНЫЙ список пакетов ПЛЮС отсутствие FAIL**, а не отсутствие FAIL: обёртка подавала `exit 0` при падении в хвосте (поймала сама движковая сессия). - **Линтер якорей гоняется ПОСЛЕДНИМ шагом, после того как код замер.** Он судит доки трёх зон, но зоны его не зовут; в этот заход нашёл 21 указатель на исчезнувший код, и правки сдвигали цели дважды подряд — включая мои собственные, уже после починки. - **Якорь разрешается тем, ЧТО он утверждает, а не номером строки, на которой лежал** (движковая сессия записала переезд по совпавшему номеру и промахнулась предметом). - **Колонка «подтверждено» отчёта, пойманного на ложных подтверждениях, снимается с доверия ЦЕЛИКОМ** — критерий, отличавший ошибочные строки от верных, назвать нельзя. - **`pkill` по имени процесса на машине с параллельными сессиями бьёт по чужим.** - **Число или «доказано» уходит владельцу только после СВОЕГО прогона.** ## ⚠ ПИНГ ЗОНЕ БЭКЕНДА (оркестратор №22, 04.09, вечер) — РЕВИЗИЯ ДОКУМЕНТАЦИИ ЗОНЫ ЦЕЛИКОМ > ⚠ **ЖИВОЕ ИЗ ЭТОГО ПИНГА ВЫНЕСЕНО СТРОКОЙ ТРЕКЕРА — ряд 489 (17.09).** Пинг адресован ЗОНЕ, которой сейчас нет > (слот свободен), и тринадцать дней он пролежал здесь неисполненным именно потому, что жил в журнале, а не в > трекере. Пере-снято приборами: пункты **1 · 2 · 6 · 10 ЖИВЫ** (README описывает инвариант через отвергаемые > загрузкой ключи · оба PUML без баннера · ратифицированная норма зоны висит на ЗАКРЫТОЙ строке 246 · пакет > языкового экрана не описан), пункт **7 ЗАКРЫТ** (красных якорей в `backend/docs/` — 0 при 327 адресах), > пять пунктов НЕ ИЗМЕРЕНЫ — они про содержание прозы и требуют чтения. > ⛔ **Сам блок НЕ выносится в архив, и это замер, а не лень:** в журнал целятся **19 якорей из чужих зон** > (движок 3, платформа 10, полигон 3 плюс мои), из них **11 лежат НИЖЕ этого блока** и съехали бы на 70 строк, > а один умер бы внутри. Чинить чужие зоны я не вправе ⇒ рез дороже пользы. Тело остаётся на месте как фактура. Внешний ревизор прочитал `backend/README.md`, все 11 файлов `backend/docs/` (включая оба PUML текстом) и арх-доки движка от первой строки до последней. Правит ЗОНА. Порядок — по цене ошибки. **1. ⛔ `README.md:36` описывает инвариант через ключи, которые загрузка ОТВЕРГАЕТ.** «Канал adult — только permissive (fail-closed)»: `permissive:` и `channel:` — RETIRED и валят конфиг (`internal/config/models.go`, греп `LegacyPermissive`; `internal/config/pipeline.go`, греп `LegacyChannel`). Настоящий механизм — `content_labels` книги × `accepts_labels` модели — в README не назван ВООБЩЕ. Сессия, строящая маршрутизацию контента по README, получит неподнимающийся конфиг. Ту же ложь несут оба PUML. **2. ⛔ ОБА PUML БЕЗ ⚠-БАННЕРА рисуют снесённое**, при том что `docs/README.md` подаёт их как канонические диаграммы, правящиеся «одним коммитом с кодом»: exit-контракт из ЧЕТЫРЁХ кодов (в `cmd/tmctl/main.go` — коды 4, 5 и полоса 10–19), глаголов 6 против 11, `mined_delta`/`mined_rejects` как ключи `book.yaml` (RETIRED, валят загрузку), машинная `.bank-stop.json` (снесена D39.158), `Adult bool`. В заголовке обоих — «синхронизировано с D1–D39.25» при живой голове D39.195. **3. `README.md:95` называет боевой редакторский промпт `v3`** *(⚠ испр. 05.09: второй адрес этого пинга — `10-prompt-architecture.md:23` — снят, потому что этот файл ЗОНА ОРКЕСТРАТОРА и бэкенд его не правит; поправлено своей рукой)* — в `configs/pipeline-c1.yaml` метка `v4-discourse-reflow-nogenre`, и с D39.182 она НЕСУЩАЯ (`TestPromptLabelsPinTheirBytes`). Поверивший README либо бампнет v3→v4 в уже-v4 файле, либо получит красный гейт. **4. `README.md:3` обещает автоматику, которой нет:** «подсистемы не импортируют друг друга (проверяется `go list -deps`)». Сама изоляция ДЕРЖИТСЯ — проверено, — но проверки нет: `grep -rn 'go list' backend --include=*_test.go --include=Makefile` → 0, а `internal/archguard` несёт три анализатора, границы импортов среди них нет. `13-tech-debt-anchors.md` это констатирует, README нет. **5. ⚠ ОБЩНОСТЬ ПЕРЕОЦЕНЕНА, и долг без носителя.** `README.md:23` («гейты по данным, Go-веток по паре нет») и `README.md:16` («`internal/text` — script-agnostic, без языковой политики») — сверх-утверждения: `internal/text/norm.go` встраивает китайскую таблицу трад→упр, складывает катакану в хирагану и БЕЗУСЛОВНО сливает `ё→е` для ЛЮБОЙ цели (белорусская цель ломается тихо); санитайзер считает только `latinLetters`/`cyrLetters`, поэтому греческая/арабская/хинди цель получает «латинскую вставку» на каждом слове; граница слова в банке проверяется только для Latin/Cyrillic. ⇒ Ревью-вопрос «пара, которой в репо нет, без правки Go» для не-кириллической цели отвечается НЕТ, а README это скрывает. **6. Ратифицированная норма зоны держится на СНЯТОЙ строке.** `DISCLOSURE_LAW_DESIGN.md:219-221`: «Пока строка бэклога 246 открыта, новый класс вводится в полосу ТОЛЬКО вместе со сверкой… Закроется 246 — оговорка снимается». 246 ЗАКРЫТА 04.09 (D39.194) ⇒ оговорка снялась молча, и это надо подтвердить или переписать сознательно, а не по факту исчезновения строки. **7. ⚠ СЕМЬ ПРОТУХШИХ ТОКЕН-ЯКОРЕЙ В `backend/docs/` — и до сегодня их не видел никто.** Корень `backend/docs` в линтере ОТСУТСТВОВАЛ с самого его заведения; добавлен 04.09 (`docs/scripts/counts.py`, греп `backend/docs` в `lint_anchors`). ✅ **ЗАКРЫТО 05.09: все семь пере-навешены (`616a8e4` два мёртвых + `e7d6b3f` пять съехавших), `--lint` → 0.** Ниже — состояние на середине дня, читать как историю. ⚠ Прежняя редакция: «починены ДВА из семи, пять живы» (`DISCLOSURE_LAW_DESIGN.md:40-44` целят в `quality.go` · `status.go` ×3 · `bookbuild.go` — зона бэкенда, пинг в её секции). ⚠ Прежняя редакция этой строки говорила «семь пере-навешены» — **ложь, выведенная из ожидания, а не из прогона линта**; поймана внешним ревьюером. Починенные два не съехали, а УМЕРЛИ: целили в (`DISCLOSURE_LAW_DESIGN.md:264` и `MONEY_HONESTY_REPORT.md:285`) не съехали, а УМЕРЛИ: целили в `chunkrun.go`=`SourceEchoExpected: role == roleTerminologist`, подстроки которой на HEAD нет вовсе — её съел переход на `isBankRole`. Прежняя редакция этой строки перечисляла краснеющие цели и была верна ровно до починки. Прежде краснели: `DISCLOSURE_LAW_DESIGN.md:40-44` (пять целей подряд — `quality.go`, `status.go` ×3, `bookbuild.go`), `:264` и `MONEY_HONESTY_REPORT.md:285` (`chunkrun.go:40`). ⚠ Эррата D15.2 от 02.09 УЖЕ указывала мимо — гейт не мог этого увидеть по построению. Команда: `python3 docs/scripts/counts.py --lint`. **8. Ссылки «строка N» на строки, ВЫПАВШИЕ из таблицы при закрытии:** `README.md:26` (103 — фантом, снят 31.08), `pipeline.puml` (99 · 100 · 101 · 125 · 145), `DISCLOSURE_LAW_DESIGN` (246 · 238 · 239 · 194), `internal/membank/decisions.go:84` (210 — закрыта 04.09). Бэклог закрытые строки НЕ хранит, а доки зоны адресуют их как живые. **9. Мелочи с адресом:** `README.md:5` «актуализировано 01.08», тело цитирует ноты 23–28.08 · `13-tech-debt-anchors.md:174` цитирует `STACK.md` в состоянии, которого там уже нет (ручка эффорта `pro` — оба носителя датированы 04.09 и противоречат) · `SEAM_PACK_FINDINGS.md:130` «у `bank-apply` ноль вызывающих на платформе» — `platform/internal/runner/bankapply.go` строит вызов · `:1133` «два хита» → четыре · `MONEY_HONESTY_PLAN-NOTE.md:35` «22 поля» → 21 на её же HEAD. **10. НЕ ОПИСАНО, А НАДО:** пакет `internal/langscreen` (новый, на денежном пути вердиктов) в README не упомянут вовсе · карта пакетов не называет ~20 несущих файлов `internal/pipeline` (`volume.go`, `rebill.go`, `reprice.go`, `refusal.go`, `terminologist.go`, `bookbuild.go`…) и пять в `internal/store` · `cmd/tmmutate` (каталог посадок, объявленный ГЕЙТОМ; ⚠ **число из этой строки снято 06.09 — стояло «141», в дереве 211**: литерал в рабочей строке живёт дольше предмета, поэтому здесь его больше нет — счёт берётся из `cmd/tmmutate/mutations.json`) и `cmd/tmvet` не названы · цена закона раскрытия («загейчен на 40 %», Г1/Г2 не построены) в статус-борде 09 не оговорена. ⚠ **Что оркестратор поправил СВОЕЙ рукой в свою зону тем же заходом:** статус-борд `09-target-architecture.md` говорил «цикл РАЗОМКНУТ» и «канон 0.9.0» в день своего же «освежения» — оба ложны с `adf5e53`/`58bca19`; висячая ссылка на закрытую 246 в шапке секции «Бэкенд»; корень `backend/docs` в линтере. ## Бэклог > ⟶ **ПЕРЕЕХАЛ 06.09 в [BACKLOG.md](BACKLOG.md)** (ратификация — D39.218). Таблица вынесена дословно, **номера строк не менялись**: «строка N» ищется там же, чем и здесь — `grep -n '^| N |' docs/BACKLOG.md`. Заголовок оставлен НАМЕРЕННО, чтобы прежние ссылки «секция „Бэклог“ в PROGRESS» доезжали в один хоп. Счёт очереди — бюллетенем в шапке того файла; **здесь копии НЕТ** (один носитель на факт, D39.112). *(Указатели на архив-слайсы хроники — бюллетенем «Архивы хроники» в CURRENT-STATE; здесь копий нет.)* ## Бэкенд #### ⚠ ПИНГ ОРКЕСТРАТОРА №23 (17.09) — ТРИ ЯКОРЯ `backend/docs/` УЕХАЛИ ИЗ-ЗА МОЕГО ВЫНОСА; ЧИНИТЬ ВАМ, В ВАШУ ЗОНУ Я НЕ ЛЕЗУ 17.09 по заказу владельца я срезал этот журнал с 5178 строк до 634: отчёты десяти ПРИНЯТЫХ паков уехали в [`archive/PROGRESS-2026-09-07-16-backend-packs.md`](archive/PROGRESS-2026-09-07-16-backend-packs.md). Вместе с ними уехали цели трёх ваших якорей в `backend/docs/CHAPTER_STRUCTURE_DESIGN.md` (строки 1774, 1783, 1785): они целятся в строки 2880 и 1874 ПРЕЖНЕГО журнала (адреса намеренно НЕ в якорной форме: якорь на уехавшую цель — это битый якорь, а не описание битого). ⛔ **ИСПР. 17.09: адреса ниже пере-сняты ПОИСКОМ; прежние были ВЫЧИСЛЕНЫ сдвигом и неверны.** Я написал «строки 2482 и 1476 (сдвиг ровно 398 строк: рез с 415-й плюс 16 строк шапки среза)» — арифметика вместо вопроса самой строке, чем она названа; ни один из двух номеров цитат не содержит. **Найденные адреса в `archive/PROGRESS-2026-09-07-16-backend-packs.md` (4568 строк):** «копить wire-правки одним касанием» — **`:1424`** (цель якоря 1774) · обе цитаты в одной строке, включая «и больше никуда», — **`:1433`** (цели якорей 1783 и 1785). ⚠ **И почему неверный адрес здесь опасен тихо:** ваши три якоря идут БЕЗ токена, поэтому линтер проверяет только попадание номера в пределы файла — вычисленный мимо адрес позеленел бы и закрепил расхождение. Сверяйте по тексту цитаты, а не по номеру. ⚠ Я их ПОПРАВИЛ И ОТКАТИЛ ОБРАТНО, когда увидел, что лезу в чужую зону — файл сейчас побайтно равен HEAD, правка ваша. ⚠ Ниже точки реза якорей не было ни одного (пере-снято прибором перед выносом), так что больше у вас ничего не сдвинулось. #### ОТЧЁТ пака «РЕШЁННОЕ НЕ ПЕРЕ-СПРАШИВАЕТСЯ» (17.09, сессия `textmachine-main-57`). НЕ КОММИЧУ — дерево передаю оркестратору №23 **Деньги пака: $0.** Платных вызовов моделей не было ни одного. Прибор M1 открывает раннер ЧИТАЮЩИМ путём (`openRunner` с `forWrite=false`), который `models.CheckKeys` не зовёт вовсе, и не вызывает ни `runTerminologist`, ни `runClassifier`, ни `TranslateBook`. Купленное сырьё открывалось только копиями. ##### 1. Исход по КАЖДОМУ пункту заказа | пункт промта | исход | чем предъявлено | |---|---|---| | §4.1 замер M1 | **сделано**, форма предиката принята оркестратором | `backend/internal/pipeline/bankbasis_m1_probe_test.go`; числа §3 | | §4.2 базис — ИСТОЧНИК ОТВЕТОВ, не фильтр | **сделано** | пин `TestTheBasisCarriesTheBoughtAnswerRatherThanDroppingIt` сравнивает ЧЕТВЁРКУ (dst, status, type, gender) авто-банка | | §4.2 таблица читателей | **сделано, и один читатель был пропущен** — найден адверсариальным кругом, см. §4б | `TestTheBankedTypeReachesTheSheetWhenTheBasisAnswers` | | §4.2 развилка «судятся ли базисные ответы проверками спора» | **решено: ДА**, довод механизменный | `backend/internal/membank/memseed.go:888`=`if IsEngineUnsigned(b) && b.Src == c.Src` | | §4.2 `Invented` и очередь спорных | **сделано, решено раздельно, ЗАПИНЕНО** | `TestTheThreeDeclaredDecisionsAboutABasisRowAreGuarded` | | §4.3 две границы записи и порядок | **сделано** | `backend/internal/pipeline/mining.go:277`=`r.writeBankBasis(ctx, "bank-mining/signature-stop")` перед памятью флажка; `backend/internal/pipeline/bookrun.go:262`=`r.writeBankBasis(ctx, "run-finished")` | | §4.3 неудача записи КРИЧИТ | **сделано** | `ERROR` с названной ценой, прогон не роняется | | §4.4 форма отпечатка | **сделано, сильнее заказанного** | окна по ВСЕМ вхождениям; ширина — ОТДЕЛЬНОЕ пар-данное `basis_width` | | §4.4 сторож растущей книги | ⛔ **НЕ ДЕЛАЮ, с замером** — §6 | числа роста в §3 | | §4.5 условие «решено» + пин посылки ряда 487 | **сделано** | `TestBasisServesOnlyADecidedRow`, подтест `status auto WITH a rendering (backlog row 487)` | | §4.5 юниты | **отдельный проход над ВСЕМИ кандидатами**, батчер не тронут | `TestBasisUnitsGiveEveryCandidateAUnitOfItsOwn`; `CONTROL-2` печатает байты батчей | | §4.6 носитель | **таблица**, миграция v19 | `backend/internal/store/bankbasis.go:26`=`func (s *Store) BankBasisForBook` | | §4.7 поле контракта | **сделано, аддитивное; ПОЛОВИНА из двух** — §9 п.6 | `settled_earlier` в сводке и построчно | | §4.7 три лгущие фразы | **сделано** | своя фраза `SETTLED EARLIER`; `NOT ASKED` оставлена — для банк-снятых строк она ВЕРНА | | §4.8 ряд 490 страж разрыва окон | **сделано, $0** | `backend/internal/membank/memvoice.go:426`=`func TermWindowGaps` | | Ряд **130** (строка 395 промта: «Строит: **130** · **490**») | ⛔ **ЦЕЛЬ ДОСТИГНУТА ДРУГИМ МЕХАНИЗМОМ, ряд НЕ закрыт** — разбор сразу под таблицей | замер по трём предметам остатка при знаменателе 1153 | | §4.8 ряд 447 | ⛔ **НЕ ДЕЛАЮ, с замером** — §6 | | | §4.8 ряд 448 | **сделано, объявлено сменой поведения** | голден 144 → 149 строк | | §4.9 вне скоупа | не трогал | | | Приложение: онтологию правит пак базиса | **сделано** | `docs/architecture/18-bank-ontology.md:25`=`**ПАМЯТЬ РЕШЕНИЙ** — что книга уже решила` | ⛔ **РЯД 130 — исход ТРЕТЬЕГО рода, и первая редакция этого отчёта не называла его вовсе.** Ряд заказан промтом наравне с 490 («Строит: **130** · **490**»), а §13 требует исход по КАЖДОМУ пункту — то есть заказанный пункт стоял без утверждения, и нашлось это вопросом оркестратора, а не мной. ⚠ Второй случай одного класса за смену: **оба раза дыра была не в неверном числе, а в ОТСУТСТВУЮЩЕМ утверждении** (первым был прибор, не названный прибором, §8). Числа я проверяла, полноту перечня — нет. **Что пак с ним сделал — замер, а не проза** (знаменатель: изменённых строк зоны прочитано **1153**): | предмет остатка ряда 130 | изменённых строк пака | |---|---| | `writeAutoBank` · `emitRankCap` — накопительный мердж авто-банка | **0** | | `seedReject` · `mined-rejects` — освобождение слотов | **0** | | `memory_version` / `MemoryVersion` | **0** | ⇒ **Замысел ряда исполнен, механизм ряда НЕ построен, и не построен НАМЕРЕННО.** Ряд предлагал держать решение между покупками накопительным мерджем авто-банка, а тот двигает банк → `memory_version` — потому ряд и висит СТОП-решением владельца. Базис даёт то же свойство (слово владельца 16.09, `D39.254` п.1: «решение банка между покупками ДЕРЖИМ») **отдельной аддитивной таблицей, которая банк не трогает вовсе** (миграция v19). ⇒ гейт стоп-решения этим паком **не достигается по построению**, и закрывать ряд нельзя: остаток сузился до ДВУХ названных предметов — накопительный мердж и слоты seed-rejects, — а само стоп-решение как было, так и остаётся за владельцем. ##### 2. ⛔ СМЕНА ПОВЕДЕНИЯ — подаю ратифицируемо, отдельным пунктом **Что изменилось.** Первый прогон книги после появления базиса платит ОДИН раз за переупаковку хвоста батчей. Замерено по четырём прогонам одной фикстуры: run1 `$0.001820` · **run2 `$0.001820`** · run3 `$0.000000` · run4 `$0.000000`; вызовов провайдера банк-ролью 1 → 2 → 2 → 2. **Механизм.** Базис — ТРЕТИЙ вход состава батчей, и он переходит из пустого в полный на выходной границе run1. Run2 встречает состав, которого у run1 не было, не находит чекпойнта по хешу запроса и покупает пасс. ⛔ Лечение «встать в сторону у книги, которая уже платила» — ровно тот баг, который докблок `dropBankSettled` описывает своими словами: **правило, решающее иначе на втором прогоне, не есть правило резюма**. Цена ограничена `gates.terminology.budget_usd` и ОБЪЯВЛЕНА сообщением ряда 448. **Какие тесты описывали ЭТУ смену поведения и куда уехала гарантия — ТРИ, и это первые три строки §5:** `TestAResumeFindsItsCheckpointsAfterTheFilter` · `TestTheRunTotalIsThisRunsSpendIncludingTheClassifier` · `TestAutoWireIsDeterministicAndDoesNotMoveTheDraftWave`. Все три утверждали «резюм бесплатен с ПЕРВОГО раза»; теперь утверждают «со второго», и каждый обслужен так, что стал СИЛЬНЕЕ прежнего, а не слабее. ⚠ **Таблица §5 шире — в ней СЕМЬ строк, и остальные четыре к смене поведения отношения не имеют:** две двигает голова схемы 18 → 19 (`TestRowsWrittenBeforeTheThinkingColumnReadAsUnanswered` и `migrate_cli_test.go`), одну — рост поля проекции (`TestEveryDecidingFieldSurvivesTheProjection`), и одна это голден операторских сообщений под пере-формулировку ряда 448. Названо раздельно, потому что «три» и «семь» в одном отчёте без этой фразы читаются как расхождение, и приёмке пришлось бы угадывать, какое число о чём. ##### 3. ЧИСЛА — все сняты ПОСЛЕ последней правки, каждое с командой Команда (подготовка материала — в докблоке прибора, `bankbasis_m1_probe_test.go:28`, включая шаг, которого прогону A не хватает в архиве): `TM_BASIS_M1=<копия A>,<копия B> go test ./internal/pipeline/ -run TestProbeBankBasisM1 -v` | | кандидатов | предложено базису | банк-фильтр взял | **обслужено** | пере-спрошено | класс | |---|---|---|---|---|---|---| | A `bk_ROEHZBD46ALFI43E` | 69 | 68 | 1 | **67 (97 %)** | 1 | `signed-by-owner` | | B `bk_NH6275ZIRFFTLZHG` | 66 | 65 | 1 | **64 (97 %)** | 1 | `signed-by-owner` | Прочие классы пере-спроса на неизменном исходнике — НОЛЬ, включая новый `ambiguous-surface`. **Верность реконструкции (ассерт, не лог):** A — 69 против 69, B — 66 против 66, расхождений 0 в обе стороны. **Контроли, все различающие:** - **К-1:** множество пере-спрошенных совпало с НЕЗАВИСИМЫМ позиционным обходом окон — `missing=0 extra=0`. - **К-2:** состав батчей байт-идентичен, печатается РАЗМЕР рендера (910 и 903 байта). - **К-3 (сверх заказа):** `kwic_per_term 3→1`, `3→40`, `kwic_width 40→120` теряют **0, 0, 0**; положительный контроль `basis_width 40→80` теряет **ВСЕ** (67 и 64). **Цена правила юнита:** A и B — по **1** кандидату, и это подписанная строка. С экземпцией подписи (решение оркестратора) все четыре варианта правила дают одно число ⇒ на этом материале правило БЕСПЛАТНО. Форма юнитов: A — 54 юнита, 44 одиночки, крупнейший 4; B — 52, 43, 4. **`auto`-хвост (§5 п.5 промта):** **A — 0, B — 0**, с гистограммой статусов рядом (`approved:2 draft:67` и `approved:2 draft:64`, строк без ряда банка 0). ⇒ на этом материале класс **не измерен, а не отсутствует**. **Растущая книга:** базис пишется на префиксе (главы 1–2, 4 чанка из 6, 17199 из 23768 байт): | | решено на префиксе | пережило рост | пере-спрошено | своя улика выросла | держит юнит | |---|---|---|---|---|---| | A | 67 | **37 (55 %)** | 30 | 29 | 1 | | B | 64 | **32 (50 %)** | 32 | 29 | 3 | **Остаток «стык чанков» — ИЗМЕРЕН, а не назван:** бюджет сегментации ×0.5 (чанков 6 → 11) двигает отпечаток у **6 из 69** (A) и **8 из 66** (B); ×2.0 (6 → 3) — у **4** и **4**; все кандидаты в исходнике засвидетельствованы. ⇒ двукратная смена кроя стоит **6–12 %** пере-спроса, а не книги. ##### 4. Находки о МЕТОДЕ — мои собственные, по ходу работы ⛔ **(1) НУЛЕВОЕ ЗНАЧЕНИЕ КАК НОМЕР ЮНИТА.** `MergeUnits` возвращает ЧАСТИЧНУЮ карту, а движковая конвенция читает отсутствие ключа как «одиночка». Предикат индексировал её напрямую ⇒ все безюнитные кандидаты получали id **0**, то есть ОДИН юнит на 44 члена. Прибор печатал **22 из 69** и целую историю про то, что правило юнита съедает две трети экономии. Поймано НЕСОГЛАСИЕМ ДВУХ ЗАМЕРОВ об одном правиле. Класс общий и дороже числа: **частичная карта, чьё отсутствие ключа читается как значение.** ⛔ **(2) ВАРИАНТ ЗАМЕРА, НЕ ИСПОЛНЯЮЩИЙ СОБСТВЕННОЙ ПОДПИСИ** — строка «подписанные считаются решёнными» не меряла ничего: предикат отвергал строку по СТАТУСУ, и юнит оставался заблокирован. Печатала то же число, что строка над ней, и читалась как находка. ⛔ **(3) КОНТРОЛЬ БЫЛ НЕПРАВ, И ЭТО ДОКАЗАНО ВТОРЫМ МАРШРУТОМ.** Первая редакция К-1 требовала «ровно виновник и его юнит» и покраснела на живом материале: правка — это ТОЧКА, и она попадает в окно улик всякой поверхности рядом, включая те, что виновник СОДЕРЖИТ (`三转蛊师` содержит `蛊师`). Новая редакция сверяет предикат с НЕЗАВИСИМЫМ позиционным обходом окон — 0/0 в обе стороны. ⛔ **(4) МОЙ РАЗДЕЛ ТЕСТА УВЁЛ ЛОВЦА ИЗ-ПОД ЗАПИСИ КАТАЛОГА — нашёл ПОЛНЫЙ прогон.** Разделив денежный тест, я перенесла его резюм-ногу в новый тест; запись `BANKMONEY-…-cumulative-spend` осталась смотреть на старый. Тест зелёный, раздел объявлен заранее, прицельный прогон моих записей 15/15 RED — и мутация ВЫЖИЛА. **Ни один способ дешевле полного прогона этого не видел.** Запись нацелена на обоих ловцов. ⛔ **(5) РЕФАКТОР ЕДВА НЕ ОТПРАВИЛ В ОТСТАВКУ ЧУЖОЙ ДЕНЕЖНЫЙ ПИН, и это моя ошибка второго рода.** Чиня (4), я свела три копии пере-ранжирования в один хелпер — код стал лучше, а чужая запись `MONEY-the-rescoring-is-applied-to-the-filtered-copy` перестала резолвиться: она сажает мутацию в ЛИТЕРАЛЬНЫЕ три строки. Пере-нацелив её на хелпер, я получила **выжившую** — потому что внутри хелпера нет отфильтрованной копии, и посадка стала «не пере-ранжировать вовсе», то есть ДРУГИМ дефектом, который никто не пинит. ⇒ **откатила рефактор в обоих пред-существующих местах и восстановила чужую запись байт-в-байт из HEAD**; хелпер остался только у моего нового вызывающего и объясняет в комментарии, почему НЕ поглотил соседей. Норма, которую это купило: **рефактор, уводящий предмет пина из-под его посадки, тихо отправляет пин в отставку — и «улучшение кода» здесь не довод.** ##### 4б. Адверсариальный круг по СВОЕЙ готовой работе (§5 промта) — 9 находок, все подтверждены моим чтением Контролёр поднят один, по §5 промта. Каждую находку я пере-проверил сам, прежде чем принять; ни одна не отвергнута. | находка | класс | что сделано | чем предъявлено | |---|---|---|---| | **ТИП из базиса не доезжает до ЛИСТА:** слияние стоит ПОСЛЕ `applyTypes`, поэтому на листе `place`, а в банке того же термина `term` — в установившемся режиме | мажор; пропущенный читатель (ровно то, о чём предупреждал §4.2) | базисный тип штампуется на кандидатов ДО листа, отдельной функцией, чтобы не раздуть `reclassified` | `TestTheBankedTypeReachesTheSheetWhenTheBasisAnswers` + запись `BASIS-banked-type-never-reaches-the-sheet` | | **`EvidenceWindows` КВАДРАТИЧЕН:** `window()` пере-строит рунный вид ВСЕЙ книги на каждое вхождение; ×4 исходник → ×15 времени | мажор; вдобавок новый вызывающий молча снял условие ЧУЖОГО вывода («strings are chunk-sized») | источник конвертируется в руны ОДИН раз; равенство окон с `window()` запинено отдельно | `TestEvidenceWindowsDoesNotGrowQUADRATICALLY…` (ratio ×3.2 при ×4) + `TestEvidenceWindowsCutsTheSameWindowAsKWIC` | | **ПОДПИСАННАЯ строка получала запись в базис:** снимут подпись — базис подаёт слово движка поверх слова владельца | мажор; вторая петля, которую онтология объявляет защищённой | запись отказана при `status == "approved"`; текст онтологии приведён в соответствие | `TestTheOwnersSignedRowIsNeverRecordedInTheBasis` + запись `BASIS-records-the-owners-signed-rendering` | | **Индекс банка СХЛОПЫВАЛ (src, sense, since, until) в один src:** побеждала последняя строка, подпись на одном окне становилась невидимой | мажор; **второй случай класса «нулевое/отсутствующее читается как значение»** | неоднозначная поверхность ОТКАЗАНА, а не угадана: свой класс `ambiguous-surface`, отказ и на чтении, и на записи | `TestAnAmbiguousSurfaceIsReAskedRatherThanGuessed` + запись `BASIS-collapses-two-senses-of-one-surface` | | **Один кандидат мог нести ОБЕ метки** (`never_asked` и `settled_earlier`): две взаимоисключающие фразы на листе, двойной счёт, и — хуже всего — вынос из очереди спорных по `SettledByBank` | средний, но следствие денежное | базису предлагаются ТОЛЬКО кандидаты, которых не взял банк-фильтр | `TestASettledRowIsNotAlsoMarkedNeverAsked` + запись `BASIS-and-the-bank-filter-claim-the-same-row` | | **`basis_width` — пар-данное, которым пак отвечает на ревью-вопрос канона, — не стерёг НИКТО:** мутация «читать `kwic_width`» выжила весь тест-набор | средний; пин гонял только ветку ДЕФОЛТА | пин с настоящим паком | `TestBasisWidthIsReadFromThePairWhenThePairStatesIt` + запись `BASIS-width-read-from-the-prompt-knob` | | **Три объявленных решения не ловило ничто** (подавление `Invented`, отказ от экземпции в очереди спорных, порядок разбора меток) — все три посадки выжили | средний ×3; «объявлено в комментарии» ≠ «стережётся» | один пин на три, каждое с контролем | `TestTheThreeDeclaredDecisionsAboutABasisRowAreGuarded` + три записи каталога | | **Строка прибора «(the design)» НЕ была дизайном:** её `count()` блокировал юнит на `basisSigned`, а движок его исключает ⇒ печаталось 62 там, где движок даёт 64 | средний; ровно класс, который запрещает докблок этой же функции | вариант исполняет свою подпись; строки переименованы | строки `UNIT-RULE` в §3 | | **Рецепт в докблоке прибора КРАСНЫЙ на этой машине** для прогона A (в архиве нет `mirror/prompts`) | минор, но делает половину замера невоспроизводимой | рецепт дополнен шагом сборки, с доводом, что это ВОССТАНОВЛЕНИЕ архива, а не выбор входа | докблок `bankbasis_m1_probe_test.go:28` | Плюс три минора прозы, закрытые: «`basisWidth` mirroring `terminologyOpts`» (у него ДВЕ ступени, не три, и это намеренно), «банк читается ОДИН раз за роль» (пред-существующее второе чтение в `dropBankSettled` названо), мёртвая привязка `_ = terminologyCallsAfterFirst` заменена на живое утверждение о вызовах. ⚠ **Что контролёр оставил НЕПРОВЕРЕННЫМ, а я проверил исполнением:** - «влияет ли на кого-нибудь `res.Gendered`, который считается ДО слияния базисных родов» — **дефекта нет, и это ЗАМЕР, а не рассуждение:** `res.Gendered = len(gendered)` стоит на `terminologist.go:552`, слияние — на `:826`, то есть счётчик меряет ровно то, что обещает его докблок («сколько кандидатов получили род ОТ КЛАССИФИКАТОРА»), и базисные роды в него не попадают намеренно — тот же принцип, что у `Reclassified`. - моё же утверждение «между двумя чтениями банка глоссарий никто не пишет» — **пере-снято прибором:** единственный не-тестовый вызывающий `ReplaceBank` — `backend/internal/pipeline/seeding.go:42`=`if err := r.Store.ReplaceBank(r.Book.BookID, in.entries, in.voices, in.pairs)`, то есть `seedGlossary`, и в промежутке он не бежит. ⚠ **Что контролёр НЕ смог проверить, и я это НЕ закрываю молчанием:** полную батарею с `-race` и полную мутационную кампанию он не гонял (дорого); три его посадки прогнаны по двум пакетам, а не по модулю. Обе дыры закрыты МОИМИ прогонами, числа в §8. ##### 4в. Круг ПРИЁМКИ оркестратора — 6 находок, все приняты и починены Приёмка №23 подняла две линзы и посадки. Каждую находку я пере-снял своим прибором, прежде чем принять; ни одна не отвергнута, и одна оказалась сильнее, чем её подали. | находка | класс | что сделано | чем предъявлено | |---|---|---|---| | **F1. Отпечаток описывает вход роли и молчит о том, КТО отвечает.** Производителя в нём нет, а денежный `RequestHash` его хеширует ⇒ до пака правка промта банк-роли давала промах чекпойнта и книга пере-покупала банк у НОВОГО производителя; после пака решённая строка не спрашивается никогда, и улучшение промта доезжает только до нерешённого хвоста — **навсегда** | мажор; **тихая потеря КАЧЕСТВА**, не денег: улучшение промта банк-роли есть прямой рычаг против translationese, цель №1 канона | производитель входит в отпечаток: `bankRoleProducer()` — модели обеих банк-ролей, общий уровень усилия и **SHA256 обоих пар-промтов**. ⚠ Снапшот НЕ берётся: он сворачивает банк, и отпечаток двигался бы на каждой строке | `TestTheFingerprintNamesWhoWouldAnswer` (четыре оси + контроль «тот же производитель — тот же отпечаток») · `TestTheProducerIdentityIsResolvedInOnePlace` · две записи каталога | | **F2. «Чьё это слово» спрошено ВТОРЫМ написанием.** У движка есть одно определение — `membank.IsEngineUnsigned` — а базис спрашивал голое `Status == "approved"` в двух местах и поля `Source` не читал ни разу | мажор; ровно тот класс, который движок запрещает у соседа. Популяция законна: сид-терм ВЛАДЕЛЬЦА со статусом `draft` загрузчик допускает и даже ТРЕБУЕТ у него передачу | `membank.IsEngineUnsigned` в обеих точках; отдельный класс `owners-unsigned-row` — «ты подписал» и «ты написал рукой и не подписал» разные фразы владельцу; экземптирован из блокировки юнита | `TestAnOwnersUNSIGNEDRowIsNotTheEnginesMemoryEither` с контролем на строке ДВИЖКА того же статуса · запись каталога | | **D1. Смена ширины улик докладывалась ЧУЖОЙ причиной.** Ширина жила только внутри хеша улик ⇒ её смена читалась как `evidence-moved`, «источник вокруг термина изменился» | средний, но про доверие к сообщению: реакции владельца на две причины ПРОТИВОПОЛОЖНЫ — одна «ничего не делать», другая «кто-то повернул ручку» | эффективная ширина входит в хранимую ФОРМУ (`basisShape`), и сообщение печатает обе формы | `TestAWidthChangeReportsItsOwnCauseAndNotTheSources` · запись каталога | | **D2. У стоп-границы не было стража.** Замер приёмки с контролем: снятие записи на `run-finished` даёт `FAIL`, снятие на СТОП-границе оставляет пакет `ok` | мажор по цене: стоп возвращается ЗНАЧЕНИЕМ-ОШИБКОЙ, до `run-finished` такой прогон не доходит ⇒ резюм после подписи пере-купил бы ВЕСЬ проход | пин на стоп-границу, с утверждением ПОРЯДКА (базис до памяти флажка) и контролем «память флажка не пуста» | `TestTheSignatureStopWritesTheBasisToo` · запись каталога | | **D3. Базис служил ответ, не сверяя его с текущей строкой банка** | средний; **популяция НАЗВАНА, а не заявлена** — на прогоне-писателе они совпадают по построению, достижимое расхождение это правка файла авто-банка рукой (онтология числит его ИСТОЧНИКОМ) | условие предиката в две строки, свой класс `bank-disagrees-with-the-memory`; сравнение под тем же фолдом целевых форм, что и голосование, — иначе движок покупал бы термин заново из-за регистра | `TestABankRowThatDisagreesWithTheMemoryIsReAsked` (+ пин на фолд) · запись каталога | | **D5. ЧЕТВЁРТАЯ лгущая фраза, и она была ЗАКРЕПЛЕНА ПИНОМ.** «Роль не спрашивали ни о чём, потому что банк уже отдаёт всех кандидатов» — для книги с базисом ложны обе половины | средний; и правка требовала обслуживания пина, то есть объявления, а не тихого редактирования | фраза различает ДВЕ причины и печатает их числа раздельно; пин обслужен и расширен до трёх случаев, включая сочетание обеих | `TestTheSigningScreenSaysHowCompleteTheBankIs` · запись каталога | ⛔ **И побочное от F2, которое я считаю находкой круга, а не издержкой починки:** фикс обвалил **пять моих собственных пинов**, потому что их фикстуры строили «решение движка» БЕЗ поля `Source` — то есть строку, которой в продакшне не бывает. Они были зелёными, потому что держали неверную посылку. Приведены к продакшн-форме (`Source: "mined"`). ⛔ **ВТОРОЙ ЗАХОД ПРИЁМКИ — ДВЕ НАХОДКИ, И ОБЕ ВНУТРИ ГРАНИЦЫ, КОТОРУЮ Я САМ ЖЕ И ПРОВЁЛ.** | находка | класс | что сделано | чем предъявлено | |---|---|---|---| | **Производитель докладывался ЧУЖОЙ причиной.** Я положил его ВНУТРЬ хеша улик ⇒ смена промта или модели давала вердикт `evidence-moved`, «источник вокруг термина изменился», — на КАЖДОЙ строке, о книге, которой никто не касался | мажор; **тот же класс, что я за час до этого починил у ширины, повторённый мной же**. И пин не ловил: он утверждал, что хеш ДВИНУЛСЯ, и не спрашивал, каким классом это доложено — зелен и пуст ровно там, где предмет | производитель — часть ПРАВИЛА, а не улика ⇒ переехал в хранимую ФОРМУ; три отдельных класса (`producer-changed` · `evidence-width-changed` · `fingerprint-shape-changed`), потому что реакции владельца на них разные: кто-то правил промт, кто-то повернул пар-данное, кто-то бампнул форму движка | `TestAProducerChangeReportsItsOwnCause` — утверждает КЛАСС, а не движение · запись каталога перенаведена | | **В отпечатке не было БРИФА, а роль его читает.** Идентичность бралась с SHA ШАБЛОНА, тогда как пар-промт рендерит `{{title}}`, `{{audience}}`, `{{honorifics}}`, `{{transcription}}`, `{{venuti}}` ⇒ смена `honorifics: keep→adapt` пере-покупает обе волны книги через `BriefHash`, а базис продолжал бы подавать передачи, решённые под СТАРЫМ законом, в волны, купленные под НОВЫМ | мажор; ни улика, ни производитель этого не видели | идентичность берёт **отрендеренный системный промт** каждой роли. ⭐ Это пар-агностично ПО ФОРМЕ, а не перечислением полей в Go: что пара решила читать, входит само — прямой ответ на ревью-вопрос канона | `TestTheProducerIdentityIsResolvedInOnePlace` (бриф · модель · классификатор · нерендерящийся промт ≠ отсутствующая роль) · запись каталога | ⚠ **И третье, что всплыло при починке и чего никто не называл:** запись с уехавшей формой я СБРАСЫВАЛ, а сброшенная запись читается предикатом как `new` — «эту поверхность никогда не решали». То есть сводная строка называла бы причину верно ОДИН раз, а каждая строка — неверно, и обе жили бы в одном прогоне. Запись теперь хранится вместе со своей формой; цикл загрузки вынесен в чистую функцию **ровно потому, что иначе это правило нельзя спросить посадкой** — внутри прохода ему нужны хранилище, книга и раннер, а денежное правило, достижимое только сквозным прогоном, — это правило, в которое никто не сажает мутацию. ⇒ первая редакция записи под него **ВЫЖИЛА**, и это её и починило. ⚠ **Два слепых пятна производителя названы там же, где перечисляется, чего в отпечатке НЕТ:** слаг модели не есть модель (вендор двигает веса за тем же именем, и хешировать тут нечего), и пустой `reasoning` означает «дефолт вендора», который уже двигался; боевые конвейеры усилие пинят явно. ⛔ **МОЯ ПРОЦЕССНАЯ ОШИБКА ЭТОГО КРУГА, и она стоила приёмке часа.** Получив находки, я начал править дерево, НЕ ОБЪЯВИВ окна, — и приёмка в этот момент по нему мерила: её кампания на 307 записях считала час на корне, снятом до моих правок, и её числа пошли в мусор. Норма, которую это купило: **сдавший пак не трогает дерево, пока идёт приёмка, даже чиня её собственные находки — сначала объявляет окно, потом правит.** Законность правки не в том, что она правильная, а в том, что она ОБЪЯВЛЕНА: приёмка судит конкретное дерево, и дерево, движущееся под ней, превращает её отчёт в описание состояния, которого нет. ##### 5. Обслуженные пины — каждый назван, с тем, куда уехала гарантия | пин | что изменилось в поведении | куда уехала гарантия | |---|---|---| | `TestAResumeFindsItsCheckpointsAfterTheFilter` | резюм ТОЙ ЖЕ покупки стал «$0 со второго» | два прогона → три: run2 ОБЯЗАН объявить разовую цену И дойти до провайдера, run3 обязан быть $0 и не звать его. Пин сильнее прежнего: вторую ось прежняя форма не выражала | | `TestTheRunTotalIsThisRunsSpendIncludingTheClassifier` | — | **разделён на два.** Одной фикстуре нужен бюджет, РЕЖУЩИЙ батч, другой — с ЗАПАСОМ; с базисом требования стали арифметически несовместимы (перебор 0.0037 / 0.005 / 0.006 / 0.008). Оба утверждения живы | | `TestAutoWireIsDeterministicAndDoesNotMoveTheDraftWave` | тот же класс | добавлен прогон переупаковки, и его ПОКУПКА утверждается | | `TestRowsWrittenBeforeTheThinkingColumnReadAsUnanswered` | голова схемы 18 → 19 | выражал «предыдущую версию» через `len(migrations)-1` — верно лишь пока та миграция БЫЛА головой; переписан на поиск миграции, добавляющей колонку | | `migrate_cli_test.go` | то же | 18 → 19, список колонок головы ПУСТ: v19 создаёт таблицу | | `TestEveryDecidingFieldSurvivesTheProjection` | выросло поле проекции | «каждое поле непусто» перенесено с ОДНОЙ строки на НАБОР: `Invented` и `SettledEarlier` не могут быть истинны одновременно | | голден `operator-messages.txt` | 6 новых сообщений + пере-формулировка ряда 448 | 144 → 149 строк. Пины сообщения держатся на КЛЮЧЕ `reconsolidated`, а не на прозе | ##### 6. ДВА ОТКАЗА, оба с замером ⛔ **Ряд 447 — НЕ ДЕЛАЮ.** Смена продуктового поведения, а не починка: фильтр платит за банкованные поверхности НАРОЧНО, потому что ответ роли читают две проверки спора, и это метки на подписном листе. Замер популяции: подписанных строк по **2** из 69 и 66 ⇒ выгода ограничена **3 %** прохода, ценой был бы разбор споров у населения, ради которого фильтр двух-условен. **Что сделано вместо** — отделено следствие, которое менять безопасно: подписанная строка больше не ДЕРЖИТ семью (покупается по-прежнему). ⛔ **Сторож растущей книги — НЕ ДЕЛАЮ, и это ответ владельцу ЧИСЛОМ.** Посылка «исходник приходит целиком» — открытый вопрос владельцу; сторож «хеш разошёлся — кричим» у растущей книги обнулял бы базис на каждом выпуске, то есть ответил бы за владельца молча. Вместо сторожа — поведение по построению и числа §3. **Что механизм делает при разошедшемся хеше: ничего особенного — он не сравнивает хеш исходника вовсе.** Отпечаток пер-кандидатный, поэтому «подменён» и «дописан» различаются автоматически. ##### 7. Рефакторинг **Отдельного рефакторинга не потребовалось**, и один начатый я **ОТКАТИЛА** — см. §4 п.5: сведение трёх копий пере-ранжирования в хелпер увело предмет чужого денежного пина из-под его посадки. Единственное движение существующего кода, которое осталось: чтение банка (`r.glossaryRows()`) поднято выше по функции, чтобы предикат и проверки спора читали ОДИН банк одного прогона; второе чтение в `dropBankSettled` пред-существует и НАЗВАНО в комментарии, а не замолчано. ##### 8. Приборы — числа и команды - **Батарея зоны**, `make battery`: **MAKE_EXIT=0**, линтер `0 issues.`, целей отработало **8 команд** (build · vet ×4 · lint · test), `go list` **24** = вердиктов **24**, `comm -23` пуст И `comm -13` пуст, FAIL **0**. ⚠ Линтер дважды ловил у меня то, что `go test` пропускал (`ineffassign`, затем `staticcheck`): `lint` стоит ДО `test`, и «все тесты зелёные» здесь ничего не значит. - **Мутации пака, прицельно** (`tmmutate -id`, 27 записей включая пере-наведённую чужую): **27/27 RED, 0 неожиданных, 0 протухших**. - **Полные прогоны каталога — их было ПЯТЬ, и я называю все, включая два несостоявшихся.** 1. **Первый, 296 записей: 295 RED · 1 SURVIVED · 0 UNKNOWN · 0 ROTTED.** Выживший — `BANKMONEY-the-run-total-reports-the-contours-cumulative-spend`, причина в §4 п.4, починен. 2. **Второй — Я ЕГО УБИЛА** (адверсариальный круг переписал предмет под ним). 3. **Третий, 307 записей: 307 RED · 0 SURVIVED · 0 UNKNOWN · 0 ROTTED.** Верен для дерева ДО круга приёмки. 4. **Четвёртый — ОБОРВАЛСЯ на 209 вердиктах из 315.** Я послала ему `kill` (круг приёмки переписал предмет под ним), и в то же окно харнесс сообщил, что остановил его по нехватке памяти. **Какая из двух причин сработала первой, я предъявить не могу**, и пишу дизъюнкцию вместо удобной определённости: несущее различие тут «оборван ≠ прошёл частично», и оно сохраняется при любой из причин. ⚠ Что при этом ТОЧНО не было причиной — потолок cgroup: `/proc/self/cgroup` даёт `0::/`, и файла `memory.max` у него НЕТ вовсе. То есть канонический класс «убил потолок собственного юнита» здесь ни при чём, и первая моя версия этой строки называла бы неверную причину дважды. 5. **Пятый, финальный, на дереве, которое я сдаю: 315 записей → 315 RED · 0 SURVIVED · 0 UNKNOWN · 0 ROTTED · 0 NOTHING, `TMMUTATE_EXIT=0`, `anchors swept: 0 of 526 entr(ies) rotten`.** Полнота сверена не хвостом лога: вердиктов **315** при **315** записях с флагом `battery` в каталоге ТОГО ЖЕ прогона. **Выживших нет. Неизмеренных нет.** ⛔ **Оба убитых в число идут НУЛЁМ, а не своей частичной выдачей**, и гашение шло по СВОИМ PID, по одному, после `ps` глазами: `go test` и `tmmutate` — имена, общие для всех зон. **Прерванный прогон не есть прогон**, и разница между «убит» и «не запускался» для акта нулевая — а вот между «убит» и «прошёл частично» огромная, поэтому названо. - **Каталог:** 492 → **526** записей, в гейте 281 → **315**. Моих — **34**, все помечены `battery`. - ⛔ **ОДИН из моих новых тестов — НЕ ПИН, А ПРИБОР, и без руки он не стережёт ничего.** `backend/internal/pipeline/bankbasis_m1_probe_test.go:57`=`func TestProbeBankBasisM1` гейчен переменной `TM_BASIS_M1` (`backend/internal/pipeline/bankbasis_m1_probe_test.go:60`=`instrument: set TM_BASIS_M1`) и не ставится НИ ОДНОЙ целью Makefile ⇒ в батарее он СКИПАЕТСЯ, и его зелень не значит ничего. ⇒ по числу новых тестов пинов у пака на один меньше, чем кажется, и следующая смена обязана прочесть это здесь, а не в докблоке файла: **в коде названо, в отчёте нет — значит для следующей смены не названо.** ⚠ Две другие env-гейченные пробы в этом пакете (`TestProbeBankBatchOrdinalShift`, `TestCorpusBankKeyConflicts`) **пред-существуют** и паку не принадлежат — провенанс снят диффом, а не грепом файла. - ⭐ **И вопрос, который за этим стоит на самом деле, задан и закрыт числом: записей каталога, чей ЛОВЕЦ env-гейчен, — 0 из 34.** Прибор в неработающем наборе — полбеды; беда — ПОСАДКА, чей ловец молчит: она даёт выжившую или «nothing ran», и обе читаются как находка о предмете. Контроль печатается рядом с нулём: env-гейченных тестов прибор нашёл в дереве **12** (в их числе `TestCheckerLabelsBaseline` и `TestCorpusBankKeyConflicts`) — то есть вопрос задан существующему предмету. ##### 9. Что НЕ удалось и где мой прибор СЛЕП 1. ⛔ **M1 не судит КАЧЕСТВО.** Отвечает «сколько строк не пере-спрошено» и ни одним числом не говорит, хороши ли сохранённые передачи. Не чинил: нужен платный судья, пак объявлен $0. Закрывается полигоном. 2. ⛔ **Замер на книге из ТРЁХ глав и одной пары.** Юниты мелкие (крупнейший 4), поэтому цена правила «семья целиком» измерена там, где ей негде развернуться. На длинной книге число может быть другим. 3. ⚠ **Стык чанков — БЫЛО слепой зоной, теперь ИЗМЕРЕНО** (§3): 6–12 % при двукратной смене кроя. Не чиню: альтернатива — вторая копия определения «нормализованный исходник», и одно определение дороже. 4. ⛔ **`basis_width` не заполнен НИ ОДНОЙ парой** (контроль: `terminology.txt` — 0 файлов при 16 прочитанных). Пар-данность построена и ТЕПЕРЬ запинена, но живьём не исполняется ничем. 5. ⚠ **Смена `basisFingerprintVersion` обнуляет базис КАЖДОЙ книги разом.** Названо в комментарии и объявляется сообщением; механизма «пере-считать отпечатки без покупки» нет, хотя он возможен ($0). Кандидат в ряд бэклога. 6. ⛔ **Поле `settled_earlier` — ПОСТРОЕНА ОДНА ПОЛОВИНА ИЗ ДВУХ.** Движковая: поле публикуется в `bank.json` — в сводке (число) и построчно (флаг). **Платформенная НЕ построена, наружу по контракту поле не отдаётся.** Платформа собирает секцию консолидации ПОИМЁННЫМ перечислением в ШЕСТИ местах, включая колонку Postgres и её миграцию ⇒ аддитивное поле движка туда не доезжает само. **Контроль:** `settled_earlier` в `platform/` — **0** файлов, соседнее `never_asked` — **8**, прибор прочёл **215** `.go`-файлов зоны. Носитель обязательства — строка трекера оркестратора. 7. ⚠ **Онтологию правил пак, ратифицирует НЕ пак.** Пятая роль и вторая петля вписаны по прямому указанию эрраты 17.09-д; страница ратифицирована `D39.158`, и её новая строка живёт под чужой ратификацией, пока оркестратор не закроет это нотой лендинга. 8. ⚠ **Три посадки адверсариального контролёра прогнаны им по ДВУМ пакетам, а не по модулю** — то есть его «выжила» означало «её не ловит ни один тест этих двух». Дыра закрыта моими прогонами (§8), но сам его вывод был у́же, чем звучал, и я это называю, а не наследую. ##### 10. Завершённость - Батарея зоны пере-снята ПОСЛЕДНЕЙ, после всех правок: `MAKE_EXIT=0`, линтер `0 issues.`, восемь команд гейта, `go list` 24 = вердиктов 24, `comm` пуст в обе стороны, FAIL 0. Контроль: файлов зоны, изменённых ПОЗЖЕ этого прогона, — **ноль** (`find -newer` по логу батареи). - Числа M1 пере-сняты после последней правки; промежуточные в отчёте не цитируются. - Дерево держит **33 пути**: **31** в зоне `backend/` (`git status --porcelain -- backend | wc -l`) плюс `docs/architecture/18-bank-ontology.md` и эта секция журнала. ⚠ Прежняя редакция называла здесь только число ЗОНЫ, и внимательный читатель прочёл его как ИТОГ: **число, которое надо складывать в уме, в секции завершённости плохое**, поэтому здесь стоят оба. - ⛔ **Про чужое — со знаменателем, потому что прежняя форма была ВАКУУМНОЙ.** Стояло «чужих путей в индексе нет» — истинно и пусто: в индексе **0** путей ВООБЩЕ, включая мои, то есть утверждение о чужом держалось на пустоте. Честная форма: **индекс пуст (0 staged)**, а в РАБОЧЕМ дереве один чужой путь — `platform/docs/DEFECT_REGISTER.md` (1 строка, ячейка платформенной зоны, закрывшая `PD-441`). Он не мой, я его не трогала, и он едет со своим лендингом, а не с моим. Не коммичу. **Работа завершена, править не планирую.** #### ЗАПИСКА-ПЛАН пака «РЕШЁННОЕ НЕ ПЕРЕ-СПРАШИВАЕТСЯ» (17.09, сессия `textmachine-main-57`). До первой правки кода, по §7 промта **Деньги: $0.** Платных вызовов моделей пак не делает. Всё ниже снято чтением дерева и купленного сырья прогонов A и B (только копии; оригиналы не открывались ничем). ##### 0. Материал замера — ИСПРАВЛЕН против промта, и исправление денежное Промт называл прогоном A `tm-coldrun-a/evidence/v16-readonly/project.db`. Это **другая книга** (`book_id: guzhenren-coldrun-v16`, и её же `book.yaml` говорит `title: … (копия для счёта форм)`). Пере-снято мной по пяти базам одной командой (`python3` + `sqlite3` `mode=ro`; поля `count(*)` по `glossary` и `checkpoints`, `sum(cost_usd)`, `max(version) from schema_version`): | база | book_id | glossary | статусы | чекпойнты | Σ cost_usd | схема | |---|---|---|---|---|---|---| | `evidence/v16-readonly` — ОТВЕРГНУТА | `guzhenren-coldrun-v16` | 53 | 41 draft + 12 auto, **0 approved** | 50 | 0.436110 | 16 | | `tm-coldrun-a/stand/books/bk_ROEHZBD46ALFI43E` — **прогон A** | `bk_ROEHZBD46ALFI43E` | **69** | 67 draft + **2 approved** | 33 | **0.419423** | 16 | | `tm-coldrun-b/stand/books/bk_NH6275ZIRFFTLZHG` = `evidence/paid-final-project.db` — **прогон B** | `bk_NH6275ZIRFFTLZHG` | 66 | 64 draft + **2 approved** | 34 | 0.396657 | 18 | ⛔ **Почему это не «поправка адреса», а спасённое число.** У отвергнутой базы подписанных строк **ноль**, у обеих настоящих — по **две** (`方源` и `古月山寨`, они же в `bk_*.mined-delta.yaml` обоих прогонов). Класс пере-спроса «родня подписанных» уехал бы в отчёт **непопулированным по материалу, где его физически нет**, и ноль читался бы как замер. Это тот самый отрицательный замер, не доказавший, что спросил существующее. ⚠ Условия работы с сырьём, пере-снятые мной, а не принятые на слово: - копии сняты `cp -a` каталогами целиком (с сайдкарами, `-wal`, `-shm`); `project.db-wal` = **0 байт** у обоих, то есть копия одного файла и так была бы актуальна — проверено, а не предположено; sha256 баз оригинал↔копия совпали (A `527ebba330d88eda`, B `90097e39ca6ffa8e`); - схема A — **16** при голове 18 (ряд **475**): `OpenReadOnly` её отвергнет, `Open` мигрирует. Аддитивность миграций пере-снята мной по телу `backend/internal/store/migrate.go`: v17 — `CREATE TABLE IF NOT EXISTS wave_selection` плюс индекс, v18 — `ALTER TABLE request_log ADD COLUMN reasoning_in_completion`; разрушающих глаголов ноль, единственное совпадение `drop` во всём файле — слово в ПРОЗЕ комментария (контроль: в файле 717 строк, `create table if not exists` — 17, `add column` — 21, то есть прибор файл прочёл); - `book.yaml` обоих прогонов ссылается на `/home/ubuntu-26/…`, которого на машине **НЕТ** (`ls -d` → `No such file or directory`); работаю на копии `book.yaml` с путями в зеркала прогонов. Значения `contrast_path`, модели банк-ролей и `kwic_*` печатаю рядом с числами — иначе «тихо взялись конфиги головы» неотличимо от «взялись конфиги прогона»; - исходник обоих прогонов байт-идентичен (`sha256 ed870ba6065ce3eb…`, 17564 байта), декодирую его не харнессом, а движковым `ingestSource` + `chunk.SplitChunksWithChapters`. ##### 1. Форма носителя — ТАБЛИЦА ХРАНИЛИЩА, аддитивной миграцией. Довод Консилиум писал букву «файл рядом с базой» (`bank-basis.yaml`). **Беру таблицу**, и довод не про вкус: 1. **Роль носителя в онтологии.** Файл рядом с базой (`auto-bank`) принадлежит роли **ИСТОЧНИКИ** — тому, из чего пересобирается вид (`docs/architecture/18-bank-ontology.md:21`=`**ИСТОЧНИКИ** — то, из чего банк собирается`). Базис источником не является: из него не собирается ни одна строка банка, его читает предикат. Класть память решений в каталог источников значит завести источник, который ничего не порождает, — а онтология судит носитель с несовпавшей ролью так же строго, как проекцию без читателя. ⛔ **ИСПР. (поймал оркестратор, опора была моя и ложная).** Первая редакция этого пункта опиралась на «у класса „ПАМЯТЬ РЕШЕНИЙ“ уже есть построенный член, и он таблица — память флажка». Это НЕВЕРНО, и пере-снято мной: «ПАМЯТЬ РЕШЕНИЙ» живёт ровно в одном месте живого дерева — эррата 17.09-д в шапке журнала решений (`docs/architecture/05-decisions-log.md:227`=`а читает денежный предикат ДО первого платного вызова`), и заводит она НОВЫЙ класс ИМЕННО ПОТОМУ, что память флажка подписана у́же («что стоп уже предъявлял», писатель — стоп). ⇒ у моего класса построенных членов нет, он первый, и опираться было не на что. Вывод «таблица» от этого не меняется — он держится на роли, а не на прецеденте. ⚠ Контроль замера напечатан: «ПАМЯТЬ ФЛАЖКА» нашлась в 3 файлах из 132 прочитанных прибором, то есть прибор искал в живом дереве, а не в пустоте. 2. **Деньги.** Предикат — денежный гейт перед первым платным вызовом. Файл рядом с базой правится рукой и ничем не отбивается; строка таблицы — нет. 3. **Перенос в книгу-продолжение** (`D39.256`, ряд **461**) переносит подписанное ПЛЮС решённое движком. Решённое, живущее в базе, переносится тем же механизмом, что и глоссарий; отдельный файл потребовал бы своего. ⛔ **Что у образца НЕ берётся вместе с формой — называю, потому что копировать механизм и не перенести его гарантию здесь уже стоило пака:** - у образца набор **только РАСТЁТ, удаления нет намеренно**. Базису это НЕ подходит: строка, решённая заново, обязана ЗАМЕНИТЬ прежнюю запись, иначе предикат будет сверяться с протухшим отпечатком. ⇒ `INSERT … ON CONFLICT DO UPDATE`, и это **новое свойство**, а не наследованное; - **общей транзакции с чекпойнтами у образца НЕТ** — пере-снято мной: слово `checkpoint` в `backend/internal/store/stopmemory.go` встречается **0** раз при 55 строках файла. Я такой транзакции тоже не строю; окно краша закрывается ПОРЯДКОМ записи (см. §3), а не атомарностью с чужим носителем. ##### 2. Форма отпечатка Отпечаток — хеш того, что читает роль, в форме, **инвариантной к способу отбора окон**: | компонента | берётся | почему | |---|---|---| | версия схемы отпечатка | константа | смена формы обязана обнулять набор ОСОЗНАННО и один раз | | `key`, эвристический тип майнера, `aliases`, `related`, `evidence` | из кандидата | это вход роли; тип берётся ЭВРИСТИЧЕСКИЙ, а не классификаторский, иначе ради отпечатка классификатор оплачивался бы каждую покупку | | окна вокруг **ВСЕХ** вхождений ключа в нормализованном исходнике, в порядке документа, ширина `kwicWidth` | из исходника | ⚠ не `c.KWIC`: тот есть ПЕРВЫЕ `maxPer` вхождений (`backend/internal/terminology/terminology.go:340`=`func AttachKWIC`), то есть подмножество, выбранное сегодняшней ручкой | | якоря канона ЭТОГО кандидата, **без капа** | `CanonFor([]Candidate{c}, canon, len(canon))` | `CanonFor` принимает батч (`backend/internal/terminology/terminology.go:856`=`func CanonFor(batch []Candidate`), и отпечаток по батчу вернул бы зависимость от состава | | **чего НЕТ:** варианты черновиков, `freq`, `since_ch`, номер главы, состав батча, кап окон | — | варианты уходят из ТРИГГЕРА, оставаясь УЛИКОЙ на листе; номер главы исключён, чтобы перекрой не обнулял базис | **Ширина — пар-данное, не константа Go.** Беру её у `terminologyOpts()`, который резолвит явный конфиг → данные пары → движковое умолчание. Константа в Go стала бы единственной шириной и была бы пар-слепой на ДЕНЕЖНОМ предикате, что прямо запрещено `D39.50` п.4. ⚠ Замер сегодняшнего состояния с контролем: `terminology.txt` в langpacks — **0 файлов** при **16** прочитанных прибором файлах, и то же в обоих зеркалах прогонов ⇒ сегодня везде работает движковое умолчание **40 рун**, и пар-данность механизма сегодня не исполняется ни одной парой. Ответ на ревью-вопрос канона: пара, которой в репозитории нет, меняет ширину своим `terminology.txt` **без правки Go**. **Три сужения, которые называю сам, потому что они невидимы:** 1. **Роль видит якорь БАТЧА, отпечаток — якорь КАНДИДАТА.** Это намеренно: замер консилиума показал батч, где якорь не относился ни к одному из шести сменившихся терминов и попал туда из-за соседей. Мы сознательно НЕ пере-спрашиваем термин из-за чужого якоря. 2. **Окна считаются по исходнику целиком, а не по чанкам.** Чанковые окна усекались бы на границе чанка ⇒ отпечаток зависел бы от кроя. Инвариантность к перекрою — заявленное свойство, и достигается она здесь. 3. **Растущая книга.** Дописанные главы добавляют вхождения ⇒ отпечаток терминов, встречающихся в новом тексте, МЕНЯЕТСЯ, и они пере-спрашиваются; термины, которых в дописанном нет, остаются решёнными. Это поведение по построению, а не сторож. ⚠ Сторож «хеш исходника разошёлся — кричим» я **строить не намерен** (см. §6), и цену этого поведения замерю числом: усечение исходника до глав 1–2 против полных 1–3 даёт долю терминов, чей отпечаток уехал, — это прямой ответ на открытый вопрос владельца, а не оценка. ##### 3. Две границы записи и порядок Писатель **ОДИН — прогон**; выходных границ у него **две**: `backend/internal/pipeline/bookrun.go:258`=`r.exportBank(ctx, "run-finished")` (под `backend/internal/pipeline/bookrun.go:254`=`if err == nil {`) и `backend/internal/pipeline/mining.go:270`=`bank-mining/signature-stop`. Одной мало по коду: стоп подписи возвращается ЗНАЧЕНИЕМ-ОШИБКОЙ (`backend/internal/pipeline/waverun.go:185`=`return nil, &WaveSignatureStop{`), то есть до `run-finished` такой прогон не доходит и резюм после подписи оплатил бы весь проход. **Порядок на границе стопа:** карта → таблица стопа → проекция банка → **базис** → память флажка. Довод берётся у самого кода: `backend/internal/pipeline/mining.go:278`=`a crash between the two costs one benign re-stop` — последней пишется запись, чья потеря ДЕШЕВЛЕ. Потеря памяти флажка стоит одного доброкачественного стопа; потеря базиса — пере-покупки банк-ролей из ПОЖИЗНЕННОГО потолка (ряд **356**). ⇒ базис раньше. ⛔ Писать базис сразу после платного прохода, ДО развилки, нельзя: базис на краш-резюме сожмёт состав батчей, чекпойнты не найдутся, и резюм перекупит оплаченное. **Ветка отказа:** стоп остаётся стопом, а неудача записи базиса **кричит** — это денежное событие. ##### 4. Таблица читателей ответа — кто получает своё, когда роль не спрашивали ⛔ **Базис — ИСТОЧНИК ОТВЕТОВ, а не фильтр,** и подставляет он **консолидированную** передачу, а не любую непустую: `backend/internal/miner/miner_emit.go:274`=`The mode turns on the CONSOLIDATED dst only, never on a raw` объясняет, почему режим `draft` включается только ею. | читатель | адрес | что получает | |---|---|---| | `attachConsolidatedDst` → режим эмиссии | `backend/internal/pipeline/terminologist.go:1415`=`Terms the role did not answer are left untouched` | передачу ⇒ `draft` вместо отката к догадке куска | | `attachClassifiedType` / `attachClassifiedGender` | `backend/internal/pipeline/terminologist.go:1430`=`attachClassifiedGender stamps` | тип и род из базиса | | `consolidatedRows` → `ConsolidationKeyConflicts` | `backend/internal/pipeline/terminologist.go:747`=`membank.ConsolidationKeyConflicts(consolidatedRows(cands, out), bank)` | судится, см. решение ниже | | `CanonConflicts` | `backend/internal/pipeline/terminologist.go:725`=`terminology.CanonConflicts(cands, out, canon)` | судится, см. решение ниже | | `ConsolidationConflicts` (§G2, свои против своих) | рядом, тот же цикл | судится | | `labelRows` → `TypeLabelMismatches` | там же | судится | | счётчики `Consolidated`/`Declined`/`Unanswered` | `backend/internal/pipeline/terminologist.go:719`=`res.Consolidated++` | ⛔ НЕ вливать базисные в общий набор до цикла счёта: поле сменит смысл без единой строки об этом | | таблица стопа и её сайдкар | ⚠ ИСТОРИЧЕСКОЕ (до этого пака формула была `row.Invented = dst != "" && !proposedByDrafts(dst, c.Variants)`, и адрес намеренно НЕ в якорной форме: цель не уехала, а ИЗМЕНИЛАСЬ — её починил этот пак, и подставить найденный в цели токен значило бы подогнать якорь под то, что там оказалось). Живая строка — `backend/internal/pipeline/mining.go:525`=`row.Invented = dst != "" && !row.SettledByBasis` | отдельное состояние, см. ниже | | очередь спорных | `backend/internal/pipeline/stopcontest.go:83`=`if r.SettledByBank` | ⛔ решается ОТДЕЛЬНО, не наследуется по совпадению имени | | проекция банка наружу | `backend/internal/pipeline/bankexport.go:128`=`NeverAsked: t.BankSettled` и `backend/internal/pipeline/bankexport.go:269`=`Contradicts: row.Contradicts, BankHolds: row.BankHolds` | АДДИТИВНОЕ поле, см. §5 | ##### 4а. РЕШЕНИЕ по двум проверкам спора (развилка §4.2 промта): **ДА, базисный ответ ими судится** Довод механизменный, а не вкусовой, и каждая половина проверена чтением: - `ConsolidationKeyConflicts` **пропускает собственную неподписанную строку движка на том же ключе уникальности** (`backend/internal/membank/memseed.go:888`=`if IsEngineUnsigned(b) && b.Src == c.Src`). Базисный ответ — ровно она ⇒ ложного спора с самим собой не возникает **по построению**. Срабатывает проверка только против ЧУЖОЙ строки — подписанной или с другим окном, — а это и есть нужная владельцу метка; - `CanonConflicts` срабатывает только при СТРОГОМ вхождении подписанного исходника в ключ кандидата (`strings.Contains(c.Key, n.Src)`), а подписанные строки входят в отпечаток (§2, якоря канона без капа, и отношение `CanonFor` ШИРЕ отношения `CanonConflicts` — вхождение в обе стороны плюс общие знаки). ⇒ у базисно-решённой строки набор канона по определению не менялся, и вердикт тот же, что на покупке, которая её купила: это НЕ новый шум. А если подпись родни появилась — отпечаток уехал, и строка пере-спрошена ПЛАТНО, то есть проверка судит свежий ответ. Альтернатива («нет, не судится») убирает метку у того самого населения, ради которого фильтр сделан двух-условным, и лист замолчал бы о настоящем расхождении только потому, что ответ пришёл из памяти. Обе проверки $0 и никогда не гейт. ##### 4б. РЕШЕНИЕ по `Invented` и очереди спорных `Invented` сегодня значит «передачу не предлагал ни один черновик». Базисная передача черновиками ЭТОЙ покупки не предлагалась ⇒ сегодняшняя формула повесила бы на канон книги ложное «выдумано движком». ⇒ строка получает **собственное состояние** (`SettledByBasis`), `Invented` для неё не вычисляется, а рендеры печатают базисную метку вместо «INVENTED». Очередь спорных: сегодняшний `SettledByBank` молча выносит строку из очереди, потому что у неё «банк держит поверхность и все черновики согласны»; у базисной строки **обе половины ложны**, поэтому она из очереди НЕ выносится — спор о ней решается на общих основаниях. ##### 5. Наружу — аддитивное поле, и трёх лгущих фраз это касается тоже `never_asked` сегодня равно числу снятых банком и значит «сид держит поверхность и все черновики согласны». Базисные строки туда класть нельзя без смены смысла ⇒ **аддитивное поле проекции** (минор контракта; пинг платформе даёт оркестратор). Три фразы, которые для базисной строки лгут ДОСЛОВНО обеими половинами и потому правятся вместе с полем: `backend/cmd/tmctl/render.go:299`=`the bank already renders those surfaces and every` · `backend/cmd/tmctl/render.go:352`=`NOT ASKED: the bank already renders this surface` · `backend/internal/pipeline/mining.go:607`=`NOT ASKED(the bank already renders this surface and every draft agreed`. ##### 6. Юниты (§4.5) — ОТДЕЛЬНЫЙ ПРОХОД, батчер не трогаю Семьи и серии сегодня детектируются НАД `paid`, то есть ПОСЛЕ фильтра (`backend/internal/pipeline/terminologist.go:574`=`terminology.DetectFamilies(paid, fp)`), и комментарий выше объясняет причину: детектировать над полным набором значит рассогласовать юниты с батчами, из них построенными. **Но это довод про БАТЧИ, а не про предикат.** Если считать юнит над `paid`, юнит будет определён тем самым фильтром, который он питает, — круг. ⇒ юнит для предиката считается **отдельным чистым проходом над ВСЕМИ кандидатами**, батчер остаётся над `paid` и байт-идентичен. Цена названа: два разных разбиения на юниты в одном прогоне, и пин обязан утверждать, что батчер не сдвинулся. ##### 7. Денежная семантика резюма — ДВЕ ОСИ, и их нельзя смешивать 1. **Резюм ТОЙ ЖЕ покупки — $0 со второго.** Базис внутри покупки после стопа неизменен ⇒ состав батчей есть функция (кандидаты, базис, банк) ⇒ чекпойнты реплеятся. 2. **СЛЕДУЮЩАЯ покупка, где решилась хоть одна новая строка, — хвост батчей переупаковывается и платится ОДИН раз.** В класс входят: первая запись базиса, подпись владельца, строки банкноты на новых главах, разрешившаяся `auto`. ⛔ Формулировка «каждый последующий прогон за $0» **запрещена** — это ровно та ложь, которую велит убрать ряд **448**. 3. **Лестница** (`D39.259`, `gates.terminology.regenerate: 1` во всех трёх боевых конвейерах): в базис ложится ответ **ВЫИГРАВШЕЙ ступени**, а не первой. Ступень в «$0 на резюме» **не входит** — реплеится оплаченная ступень, а не покупается новая. Посылку пина `backend/internal/pipeline/bankladder_test.go:111`=`func TestAHealthyBankTableIsNeverAskedAgain` базис не ломает и обязан это утверждать отдельной строкой. ##### 8. Что я пока НЕ строю и почему — исход будет с замером, а не с мнением - **Ряд 447** (подписанная поверхность снова спрашивается во втором проходе). Это смена продуктового поведения, а не починка: сегодняшний фильтр платит за разнобой черновиков НАРОЧНО. Склоняюсь к отказу; решу числом популяции на A и B. - **Сторож растущей книги** (§4.4). Посылка «исходник приходит целиком» — открытый вопрос ВЛАДЕЛЬЦУ от 17.09. Сторож, обнуляющий базис на каждом выпуске, ответил бы за владельца молча. Склоняюсь к отказу с явным объявлением растущей книги вне скоупа; что механизм делает при разошедшемся хеше — напишу числом из §2. - **Ряд 490** (страж разрыва окон глав) — $0, беру, образец `backend/internal/membank/memvoice.go:271`=`func VoiceWindowGaps`; у образца беру и ГАРАНТИЮ: намеренный разрыв законен ⇒ исход громкая строка, а не отказ загрузки. - **Ряд 448** — пере-формулировка обязана обновить И голден каталога операторских сообщений (`backend/internal/pipeline/testdata/operator-messages.txt:141`=`terminology: this book had already paid`), и это обслуживание заказанной смены поведения (`D39.183`), а не подгонка под зелень. Объявляю заранее. - **Ряд 487** пак НЕ чинит, но посылку «решено ⇒ `draft`» пиню: без пина завтрашняя починка скачком двинет набор решённых, то есть деньги. #### ОТЧЁТ пака «ЛЕСТНИЦА ПОПЫТКИ ДЛЯ БАНК-РОЛЕЙ» (17.09, сессия `textmachine-main-12`). НЕ КОММИЧУ — дерево передаю оркестратору №23 **Деньги пака: $0.** Платных вызовов моделей не было ни одного. Все числа сняты на фикстурах и на уже купленном сырье прогона B (только чтение). ##### Что построено — по пунктам заказа | пункт | исход | чем предъявлено | |---|---|---| | §4.1 вынос лестницы в общий контур | **сделано** | `backend/internal/pipeline/attemptladder.go`; `runStage` и банк-роли — два вызывающих одной петли; пин «третьей копии нет» перечисляет вызовы `runAttempt` поимённо | | §4.1 ключ ступени — число удвоений | **сделано** | голден ЗНАЧЕНИЯ хеша (построен ДО выноса и прошёл через него зелёным — это и есть доказательство, что ключ не сдвинулся); шесть ручных посадок при постройке + три записи `BANKKEY-*`, введённые в гейт навсегда | | §4.1 параметр «допуск ступени» | **сделано** | `ladderCall.afford`; у стадии `nil` (правило — резервация), у банк-роли — ролевой суб-бюджет | | §4.1 параметр «судья ступени» | **НЕ ДЕЛАЮ, довод ниже** | — | | §4.2 ступень мимо бюджета и пробы | **сделано** | `roleBudget` — один объект на пре-флайт и на ступени, и `nil` = одиночный выстрел по построению; четыре посадки RED (допуск снят · два счёта · ступень уже оплачена · книжный потолок на ступени ≥ 1) | | §4.3 эскалация банк-ролей | **НЕ ДЕЛАЮ, довод и спецификация ниже** | — | | §4.4 тождество банк-батча | **НЕ ДЕЛАЮ, посылка ряда 478 опровергнута замером** | таблица ниже + прибор в дереве (`TestProbeBankBatchOrdinalShift`); оркестратор отказ принял и снял пункт | | §4.5 счёт ответов в итог | **сделано** | `classify_asked`/`classify_answered` + отдельное предупреждение; посадка RED | | §4.6 чистый код, рефакторинг | **сделано** | список «что отрефакторено и почему» ниже | ##### Разрез: что переехало и почему **Переехала ОДНА вещь — петля попытки.** Из `runStage` в `walkAttemptLadder` (`attemptladder.go`, 264 строки). `stagerun.go`: **+38 / −95** (`git diff --numstat`, файл 1090 → 1033). ⚠ **ИСПРАВЛЕНО ПРИ ПРИЁМКЕ, и ошибка была моя, ровно того класса, который этот отчёт и обещает не делать.** Прежде здесь стояло «−89 / +27» — число, снятое СРАЗУ ПОСЛЕ выноса и не пере-снятое после последней правки (починка `judged`/`lr`, снятие параметра `maxRegens`, правки комментариев). Отчёт при этом утверждает «числа сняты ПОСЛЕ последней правки», то есть носитель противоречил сам себе. Поймал оркестратор четырьмя замерами; пере-снято тем же прибором. ⇒ **число, снятое один раз в середине работы, обязано быть пере-снято в конце, даже когда правка «не про него»** — «не про него» есть вывод, а не замер. Всё, что вокруг петли, осталось на месте: резюм по `chunk_status`, эскалация, диспозиция, запись строки статуса — у стадии; сборка батча и разбор таблицы — у банк-роли. `runStage` из терминолога не зовётся. **Почему рефактор, а не заплатка.** Заплаткой было бы `if isBankRole { ... }` внутри `runStage` или вторая петля рядом. Обе оставляют ДВА ответа на вопрос «под каким бюджетом покупается ретрай», а бюджет входит в хеш запроса — то есть две цены на один вызов, и ни одна не краснеет. **Что стало параметром и почему именно это:** - **допуск ступени** (`afford`) — у стадии деньги стережёт книжная резервация ВНУТРИ попытки, у банк-роли фазовый суб-бюджет, решённый ДО прохода. Ступень — покупка, которой в том плане не было. - **число удвоений** — ключ ступени, общий перечислитель, параметром идёт `baseMaxTokens`. - **`stageAtEffort`** — одно написание «стадия при таком-то усилии». Появилось не для красоты: усилие входит в ключ покупки, и проба «оплачено ли» обязана спрашивать про ключ, который попытка РЕАЛЬНО возьмёт (см. находку 2 самопроверки). - **политика допуска фазы — ОДИН объект `roleBudget` (потолок · израсходованное · число ре-спросов).** Дошла до этой формы не сразу: сперва число ре-спросов было отдельным параметром `runBankAttempt`, и вынудил его живой стенд — `live_reprobe` меряет, что вернул ОДИН вызов классификатора, и все его опубликованные числа («4 прогона из 5 дают 6/6 при усилии low») про вызовы, а не про проходы; читай функция политику прохода сама, стенд начал бы молча пере-спрашивать усечённый ответ и продолжил бы печатать по-вызовные цифры. ⛔ Но два параметра оставляли инвариант «нет бюджета ⇒ нет ступени» на КОММЕНТАРИИ: вызывающий с парой `(nil, 1)` получил бы допуск `nil`, то есть все ступени без пробы и без потолка фазы, молча. Слитые в один объект, деньги и счёт разойтись не могут: **`nil` = одиночный выстрел по построению**, и стенд передаёт именно `nil`, говоря почему. ##### §4.3. Эскалация банк-ролей — не строю; вот что защищает нулевой хоп Довод отказа **не денежный**: измеренная болезнь прогона B — размышление, съевшее ПОЛНЫЙ потолок (8496/8496 ×3, 8000/8000 у всех семи выброшенных вызовов; у DeepSeek размышление считается внутри `completion_tokens`). Другая модель потолка не лечит; лечит удвоение бюджета, и на черновой стадии того же прогона оно вылечило 5 единиц из 5. Класс, для которого хоп осмыслен (`refusal` — тот же вызов на той же модели пере-откажет, D2.2), на банк-ролях имеет замеренную популяцию ноль. **Пять причин нулевого хопа — это спецификация, если владелец хоп закажет.** Прочитано в `internal_call.go` и `escalation.go`, каждая пере-снята по коду: 1. **Чужой пул.** `escalationBudgetRemains` читает `Pipeline.Escal.BudgetUSD` и `EscalationSpentUSD(книга)` — пул КНИГО-ШИРОКИЙ, принадлежит волне. Банк-хоп ел бы его молча. 2. **Способ деградации.** «these calls degrade by leaving their work unchanged rather than by paying a second model»: неотвеченный терм остаётся `auto` и ничего не портит, в отличие от чанка, который отгрузил бы брак. 3. **Предварительная сборка клиентов.** `gateModels()` кладёт в достижимые модели только модели ВКЛЮЧЁННЫХ гейтов; модель хопа туда не попадёт — и `buildClients`/`CheckKeys` её пропустят, а прогон умрёт на банк-стопе «no pre-built client» ПОСЛЕ оплаченной волны. Это уже случалось (комментарий `gateModels`). 4. **Аддитивный буфер.** `InternalCall` держит `ReasoningMaxTokens: 0`, и это безопасно лишь потому, что загрузчик ОТКАЗЫВАЕТ аддитивному провайдеру для моделей гейтов. Модель хопа потребовала бы того же отказа. 5. **Имя отказа в стоп-марке.** `ceilingStopDetail` (`cutcall.go`) утверждает, что отказ потолка называет РЕ-АТАКУ, и это верно, пока каждый прочий платный шаг ловит `errReserveCeiling` и деградирует. ⚠ Моя лестница — новый платный шаг на банк-пути, и она это условие ДЕРЖИТ: `mandatory: false`, ошибка потолка ловится вызывающим и гасится в «остальные термы без изменений». ##### §4.4. Ключ не трогаю: посылка ряда 478 не подтверждается Ряд 478 утверждает: снятие решённой строки сдвигает номера всех последующих батчей, и они покупаются заново при неизменном тексте. Пере-мерил на настоящем `terminology.Batch`. **Механика.** Упаковка жадная. Снятие кандидата из батча k либо ПОДТЯГИВАЕТ содержимое из k+1 (у всех последующих меняется ТЕКСТ, и ординал ни при чём), либо не подтягивает (не меняется ничего). Сдвиг номера при неизменном тексте требует, чтобы батч исчез ЦЕЛИКОМ из середины. Прибор лежит В ДЕРЕВЕ и повторяется одной командой (по умолчанию скипается): `TM_PROBE_478=1 go test ./internal/pipeline/ -run TestProbeBankBatchOrdinalShift -v`. | замер | батчей | untouched | content-changed | сдвинуто с тем же текстом | |---|---|---|---|---| | снятие ОДНОГО кандидата, 186 снятий в 3 режимах | 2…20 | 1494 | 958 | **0** | | снятие БЛОКА, 200 случайных, `batch_runes=400`, 60 кандидатов | 19 | 1141 | 1899 | **490** | | снятие БЛОКА, 200 случайных, `batch_runes=6000`, 66 кандидатов (боевой) | 2 | 4 | 354 | **0** | | снятие БЛОКА, 200 случайных, `batch_runes=6000`, 300 кандидатов (боевой) | 6 | 65 | 1055 | **0** | | ⭐ положительный контроль: убрать средний батч целиком | 20→19 | — | — | **18** | `batch_runes` не задан ни в одном из трёх боевых конфигов ⇒ работает движковый умолчательный 6000; на прогоне B это дало 3 батча на 66 термов (22 · 19 · 24), то есть боевой режим — строки 3–4. ⇒ **Класс ЛАТЕНТЕН, а не отсутствует. Условие, при котором вывод перестаёт держаться, называю прямо:** мелкий `batch_runes` (сотни рун) делает его живым — **490** сдвигов на 200 снятий (число прибора В ДЕРЕВЕ; 475 стояло в записке-плане и относится к throwaway-пробе с другим порядком розыгрыша — расхождение названо в самом приборе). Доминирующий драйвер пере-покупки — пере-упаковка СОДЕРЖИМОГО — ни одной из двух ветвей §4.4 не лечится и назван ограничением в самом `dropBankSettled`. ##### Судья ступени (§4.1, третий параметр) — не строю, и это не экономия Промт даёт судью ради хопа («без него хоп по «упёрся в потолок» бессмыслен»). Хопа нет ⇒ обоснование отпадает. Но есть и самостоятельный довод, и он сильнее: **у лестницы ровно одна ремедия — те же сообщения с бо́льшим бюджетом.** Таблица, пришедшая ЦЕЛОЙ при `finish=stop`, но с малой долей ответов, в бюджет не упиралась — больший бюджет ей не покупает ничего. Её лекарство — пере-спрос ОСТАТКА, то есть другой запрос, другой ключ покупки и отдельное решение владельца (`D39.254` п.2, ряд 451). ⇒ Хук `judge` в дереве НЕ оставлен: поле, у которого нет вызывающего, — обещание, которого не стережёт ни один пин. Вместо него в `ladderCall` стоит абзац, называющий, почему форменный вердикт на эту лестницу не заводится. **Что надо измерить, чтобы решение пересмотреть** (в бэклог): распределение `answered/asked` при `finish=stop` по батчам на уже купленных прогонах — данные лежат в журнале запросов, пары печатаются на каждый батч. Если доля заметно ниже 1 на нетривиальной части — строится пере-спрос остатка, не судья. ##### Ручка лендится ВКЛЮЧЁННОЙ — решение СВЕРХ заказа, РАТИФИЦИРОВАНО `D39.259` `gates.terminology.regenerate: 1` в трёх боевых конфигах (c1 · arm-glm · arm-mistral; в c2 гейта нет), пин `TestShippingPipelinesRegenerateBankRoles` стережёт значение РОВНО 1 и печатает знаменатель («3 из 4»). Норма проекта — не «новые ручки выключены», а «НЕИЗМЕРЕННОЕ денежное решение выключено, и пин называет, что измерить». `lower_effort_on_empty` лендился выключенным по названной причине: стадия, которую он двигает, — редактор, чья эхо-безопасность на пониженном усилии НЕ измерена. Здесь измерение есть, и оно снято В ТОЙ ЖЕ КЛЕТКЕ: боевой черновик c1 и банк-роли идут на ОДНОЙ модели (`deepseek-v4-flash`) при ОДНОМ усилии (`low`) — `classify_model` не задан ни в одном боевом конфиге, а `ClassifyModel == "" → Model`. Обратный прецедент тоже есть: `regenerate_echo_before_escalate` лендился = 1, и его пин стережёт единицу. **Цена включения — числами, считанными по хранилищу прогона B** (ценовая модель сверена с леджером до цента: 8000 completion + 4741 prompt по пинам `deepseek-v4-flash` дают ровно записанные $0.012646): | величина | число | |---|---| | реальная цена успешной ступени | **$0.005134** (среднее по 4 чистым вызовам классификатора, 2939 completion-токенов) | | худший случай одной ступени (снова выест удвоенный потолок 16000) | **$0.0232** | | что лестница купила бы на прогоне B (2 флагнутых батча) | реально ≈ **$0.010**, абсолютный худший ≈ **$0.046** | | структурный потолок на книгу (≤ 1 лишний вызов на батч; у B батчей 7) | ≤ **$0.162**, и сверху ролевой суб-бюджет $1.00 на фазу | | для сравнения: банковый контур прогона B / весь прогон | $0.083339 / $0.436 | ⛔ **Это решение СВЕРХ заказа, и я назвала его таковым до того, как меня спросили.** Промт заказывал лестницу и подключение вердикта; включение денежной ручки в боевых конфигах — отдельное денежное решение. Довод «за»: с ключом на нуле пак для боевых книг ИНЕРТЕН — движок продолжит вычислять вердикт и продолжит его выбрасывать. **Ратифицировано оркестратором актом `D39.259`** по этим числам. ⚠ И что этот пин НЕ утверждает: что ре-спрос работает, и что единица — верное число. Он утверждает ровно одно — что боевые ДАННЫЕ продолжают его просить. Работу механизма стерегут пины в пакете движка, а значение выше единицы отвергается не как опасное, а как **неизмеренное**. **Трата разовая на книгу, а не на прогон**, потому что ступень пишет СВОЙ чекпойнт и на всех последующих резюме переигрывается за $0. Это не довод, а пин: `TestTheExtraRungIsBoughtOnceForTheLifeOfTheBook`. Снапшот при этом не двигается — гейт терминологии в него не складывается (`snapshot.go`: упоминаний `Terminology` 0 при 11 упоминаниях `Gates.`). ##### Улика, пере-снятая мной с КУПЛЕННОГО прогона B (а не взятая из промта) Промт велит пере-снимать числа, на которых строишь решение. Основание пака — «движок вычислил вердикт и выбросил его» — я пере-сняла сама, по хранилищу прогона B, **с копии, оригинал не тронут** (mtime до и после копирования совпадает; `sqlite3` как CLI на машине нет — читала `python3`). **Контрольные величины напечатаны рядом с ответом:** строк в `request_log` — **35**, из них `stage='terminology'` — **14**; чекпойнтов терминологии — **13**. То есть ноль ниже был бы ответом, а не отсутствием предмета. | роль | исход | вызовов | $ | |---|---|---|---| | classifier | чисто | 4 | 0.020534 | | classifier | **`length`** | 1 | **0.012646** | | classifier | **`empty`** | 1 | **0.012133** | | terminologist | чисто | 8 | 0.038026 | Два вызова, которые движок САМ признал негодными, и чей вердикт выбросил: ``` role=classifier batch=0 degraded=length finish=length completion_tokens=8000 cost_usd=0.012646 tm_hit=0 role=classifier batch=2 degraded=empty finish=length completion_tokens=8000 cost_usd=0.012133 tm_hit=0 ``` **Три вещи, которые это даёт сверх промта:** 1. **`completion_tokens = 8000` у ОБОИХ** — ровно `min_max_tokens` модели `deepseek-v4-flash`. Потолок выеден до токена; это не «модель отказалась», это «размышление съело бюджет», то есть болезнь, которую лечит именно удвоение. ⭐ И удвоение даёт 16000 — то же число, которое `models.yaml` уже пинит для СОСЕДНЕЙ модели по замеру «8000 → 16000 вылечило 2 единицы из 2». 2. **`max(attempt) = 0` по ВСЕМУ банковому контуру** (все 7 позиций) ⇒ попытки с индексом 1 не существует ни у одного батча: **регенерации не было ни одной**, как и утверждалось. Это тот самый индекс, который лестница теперь покупает. 3. **$0.024779 оплачено за ничто** из $0.083339 банкового контура прогона — 29.7%. ⚠ И честная оговорка о том, чего эти числа НЕ говорят: у каждого батча в хранилище по ДВА чекпойнта при `attempt = 0`, потому что store держит и первый прогон, и резюм, купившее проход заново под другим ключом. Это ДРУГОЙ дефект (пере-покупка прохода при смене состава/снапшота), он в мой пак не входит и моей лестницей не лечится. ##### Рефакторинг без регресса — чем предъявлен Ось «что переехало и чем доказано, что поведение прежнего вызывающего не изменилось» закрывается тем, что у СТАДИИ такой прибор уже был, и он побитовый: `TestGoldenDeterminism` (`golden_test.go`) пинит на статичной книге снапшот каждой волны, **хеш запроса и тело провода каждой стадии**, строки `chunk_status` и `retrieval_state` и итоговые тексты — на свежем прогоне И на резюме. Он прошёл через вынос зелёным. Именно его отсутствие на БАНКОВОЙ стороне промт и назвал, и именно поэтому голден банк-ключа строился первым делом. Сверх него зелёными под `-race` прошли одиннадцать пре-существующих пинов ровно того механизма, который переехал: `TestABurnFollowedByARegenerationDoesNotOverBuy` · `TestAStopOnAStagesFirstCallStillReportsAnAttempt` · `TestEchoRegenReplacesTheHop` · `TestEchoRegenFiresONLYForEcho` · `TestEchoRegenBudgetMovesNoSnapshot` · `TestTheRetryForAnEmptyReplyBuysLessThinkingNotMoreBudget` · `TestRetryableSubset` · `TestLabelledRefusalEscalatesThroughChainAndRegates` · `TestRunnerEscalationBudgetExhaustionDeniesLaterHop` · `TestABurnedHopKeyDoesNotBuyAHopOutsideTheEscalationBudget` · `TestAStopOverAnEscalationHopLeavesAMarkAndIsRedone`. ##### Самопроверка исполнением: круги и что они нашли Кругов было три: постройка прибора → вынос и банковая половина → приёмочный адверсариальный проход (свой плюс старший советчик). Найдено у СЕБЯ, и часть — уже в готовой работе: | находка | что сделано | чем предъявлено | |---|---|---| | **Голден хеша был ложно-зелёным**: сообщения короткие ⇒ потолок упирался в пол `MinMaxTokens`, вся арифметическая ветвь формулы в ключ не входила; посадка `terminologyReplyFloor` 256→257 оставляла файл ЗЕЛЁНЫМ | батч 0 сидит В полу, батч 1 его перерастает; ПОСЫЛКА утверждается внутри теста, иначе фикстура тихо съедет в один режим | запись каталога `BANKKEY-bank-reply-floor-moves-the-budget` — RED | | **Проба оплаты и цена ступени считались по ИСХОДНОМУ усилию, а покупка шла по пониженному** (усилие входит в ключ ⇒ ложное «оплачено» проносит ступень мимо суб-бюджета, ложное «не оплачено» выбрасывает уже купленную) | `admitLadderStep` получает стадию попытки; одно написание `stageAtEffort` | нашёл советчик-фабл; сегодня недостижимо у обоих вызывающих, и это НАЗВАНО (см. «где прибор слеп») | | **Мой литерал базового бюджета фикстуры был неверен** (512 против реальных 564), а «проверявший» его тест мерил ПУСТОЙ батч — то есть согласился со мной про другой объект | литерала нет вовсе: фикстуры учат базу у ПЕРВОГО вызова и утверждают ОТНОШЕНИЕ (удвоение) | `askedBudgets.doubledOnce` | | **Две посадки СДОХЛИ, ничего не измерив**: снятие `if cls.ok() { break }` — no-op (ok-ответ и так падает в финальный `break`), снятие `retryable()` — тоже no-op (ok-break срабатывает раньше) | посадка сделана СОСТАВНОЙ из обеих правок; в `why` записано, что ни один из двух гардов не является несущим ПООДИНОЧКЕ | `LADDER-healthy-reply-keeps-climbing` — RED | | **Фикстура суб-бюджета не различала «общий счёт» и «два счёта»**: потолок был равен цене ступени 0, и ступень 1 отвергалась при любой реализации | потолок берётся равным цене СТУПЕНИ 1, прочитанной из строки лога самой лестницы | `LADDER-pre-flight-and-rungs-count-different-money` — RED | | **Мёртвое поле** `roleBudget.role` (писалось, не читалось) | удалено | — | | **Смена сигнатуры сломала стенд под тегом `live`**, а мой `go vet ./internal/pipeline/` этого НЕ ВИДИТ: он не компилирует файлы за билд-тегом. Поймал гейт зоны (`go vet -tags live`, `MAKE_EXIT=2` при НУЛЕ строк `FAIL`) | стенд переведён на новый шов и получил `maxRegens: 0` с объяснением, почему у него другая граница измерения | `go vet ./...` и `go vet -tags live ./...` зелёные; батарея ниже | | **`nil`-бюджет превращался в колбэк, который его же разыменует** | сперва nil-проверка, затем — по существу (строка ниже) | — | | ⛔ **РЕГРЕСС, КОТОРЫЙ ОТКРЫЛА САМА ЛЕСТНИЦА: отказ КНИЖНОГО потолка на ступени ≥ 1 выбрасывал ОПЛАЧЕННЫЙ ответ ступени 0.** До пака ошибка на этом пути означала «ничего не куплено», и `break` без записи текста был всей правдой. С лестницей ступень 0 может быть куплена, классифицирована и держать частичные строки — ровно те «4 из 22», ради которых пак и заказан, — а батч читался как невызванный | на `errReserveCeiling` при `judged > 0` текст сохраняется, `ran[i]=true`, `unusable++`; WARN называет, сколько ступеней этот батч успел оплатить, и что это КНИЖНЫЙ потолок, а не фазовый | нашёл советчик, подтверждено чтением; **запинено** `TestABookCeilingOnALaterRungKeepsWhatTheEarlierOneBought` (потолок меряется двумя пробами: расход по ступень 0 включительно + цена ступени 1 из строки покупки) и записью каталога — RED | | **Инвариант «нет бюджета ⇒ нет ступени» держался КОММЕНТАРИЕМ**: вызывающий с парой `(nil, 1)` получил бы `afford == nil`, то есть все ступени без пробы и без потолка фазы — молча | политика фазы стала ОДНИМ объектом: `regens` живёт в `roleBudget`, `nil` = одиночный выстрел ПО ПОСТРОЕНИЮ; параметр `maxRegens` убран | — | | **Потолок в фикстуре суб-бюджета стоял РОВНО на цене ступени 1**, а тест читает её из строки лога, отрендеренной `%.6f` ⇒ поимка мутанта решалась последним битом округления | потолок `est1 + est0/2` — запас на порядки выше шага округления, обе стороны различения целы | `LADDER-pre-flight-and-rungs-count-different-money` | | **Посылка «фаза уже перерасходовала» строилась из КНИЖНОГО расхода**, а `roleBudget` стартует с РОЛЕВОГО ⇒ фикстура утверждала соотношение, которого не проверяла | берётся `RoleSpentUSD(роль)`, и посылка утверждает именно её | `TestAnAlreadyBoughtRungIsNeverLostToTheBudget` | | **Имя теста обещало «ОДИН раз за жизнь книги», а фикстура держала постоянным СОСТАВ БАТЧА** — а состав в бою меняется обычным порядком (вырос набор черновиков · владелец подписал терм) | тест переименован в `…OnceForABatchComposition`; комментарий и абзац в `pipeline-c1.yaml` называют условие прямо, а не в скобках | — | | **Ложное утверждение в боевом конфиге**: «считается против суб-бюджета фазы, НЕ против книжного потолка». Резервация внутри попытки судит книжным потолком КАЖДУЮ ступень | «поверх книжного потолка, а не вместо него» | — | | ⛔⛔ **МОЙ РЕФАКТОР МОЛЧА ОБЕЗДВИЖИЛ ЧУЖОЙ ПИН, и увидел это ТОЛЬКО полный прогон каталога.** Вынос петли сделал `judged` переменной с ЕДИНСТВЕННЫМ читателем — отложенной стоп-маркой. Пре-существующая запись `CUTCALL-a-stop-over-the-hop-leaves-no-mark` удаляет марку ⇒ `judged` становится неиспользованной ⇒ пакет НЕ СОБИРАЕТСЯ ⇒ харнесс печатает «nothing ran» вместо поимки. ⚠ Якорь при этом СОВПАДАЛ, поэтому контроль «все правки разрешаются уникально» был зелёным и ничего не знал | `lr` объявлен до марки, счётчик читается как `lr.judged`, локальная копия убрана: удаление марки оставляет `lr` с другими читателями. У места написано, почему счётчик читается с носителя, а не копируется | запись снова меряет; прогнана поимённо | | ⛔ **Своя запись, которую я НЕ проверила поодиночке** (`LADDER-admission-forgets-the-paid-probe`, заведена в приёмочном круге и не попала в верификационный набор). Замена `if paid {` → `if false {` оставляет `paid` объявленным и неиспользованным ⇒ та же «nothing ran» | `paid && false` — тот же дефект, но собирается; причина записана в `why` | прогнана поимённо | | ⛔ **Ложное утверждение в `why` записи каталога**: я написала, что снятие `retryable()` поодиночке — no-op. **Проверила исполнением: это неверно.** Посадила одну эту правку и прогнала ВЕСЬ пакет — красное, `TestRunnerCoverageGateFlagsExcision`: детерминированный флаг (excision) при `regenerate: 1` покупает лишний вызов на той же модели до хопа, то есть ровно D2.2 | `why` исправлен; заведена ОТДЕЛЬНАЯ запись `LADDER-retryable-gate-lets-a-deterministic-flag-re-buy` со своим катчером | RED | ##### Что советчик утверждал, а дерево опровергло Советчик — не источник истины, и две его посылки я проверила и ОТКЛОНИЛА: 1. **«Одиночное снятие `retryable()` не ловит ни один тест дерева».** Неверно: пакет краснеет на `TestRunnerCoverageGateFlagsExcision` (`regenerate: 1` + детерминированный excision-флаг). Проверено посадкой и прогоном ВСЕГО пакета, а не рассуждением. ⚠ Почему ошибка вышла у нас обоих: мутационный харнесс гоняет каждую запись с `-run <тест>`, поэтому моя одиночная проба показала SURVIVED — она спрашивала ОДИН тест. Сам класс советчик назвал верно, и запись каталога он заслужил. 2. **«Значение `regenerate_before_escalate` в боевых конфигах не запинено».** Неверно: `internal/config/echoregen_shipping_test.go:49` утверждает `!= 1` по четырём боевым файлам. ##### Унаследованное, названное и НЕ чинимое этим паком На отказе книжного потолка цикл покупки делает `break`, и вместе с отказанным батчем теряются батчи ПОЗАДИ него — включая уже оплаченные, чей повтор стоил бы $0. Это противоречит правилу, которое сам пре-флайт объявляет у себя («ADMISSION IS PER BATCH, NOT A PREFIX»), но существовало до пака и моей лестницей не создано: адрес — ветвь `errReserveCeiling` в `runBankRoleBatches`. ⚠ И вторая половина, чтобы следующая смена не искала её сама: такие батчи не попадают НИ в `dropped`, ни в `ran` — единственный их след это WARN. Не чиню, потому что это смена поведения, которой пак не заказывал; называю, чтобы следующая смена нашла решение, а не щель. **Оркестратор завёл это рядом 481** — то есть находка пережила мой контекст, чего от «названного, но не заведённого» ждать нельзя. ##### Мутации Каталог: было 478 записей / 267 в гейте, стало **491 / 280**. - **7 записей пере-нацелено** — их цели переехали вместе с петлёй из `stagerun.go` в `attemptladder.go`. Каждая сверена ПО СМЫСЛУ с новым текстом, а не подогнана под совпадающую строку. - **13 записей заведено** под новый код, **все 13 помечены `battery`** — разовым прогоном смены они не остаются. По предметам: лестница банк-роли (есть/нет · воздержанность на здоровом ответе · D2.2-гард) · деньги ступени (допуск снят · два счёта · ступень уже оплачена · книжный потолок на ступени ≥ 1) · ключ покупки (ординал · индекс попытки · пол ответа) · счётчики (доля ответов · негодный батч · отказанная ступень). - **Контроль целостности:** все **502** правки каталога разрешаются в дереве уникально. - ⭐ **ПОЛНЫЙ ПРОГОН БАТАРЕЙНОГО ПОДМНОЖЕСТВА ПРОЙДЕН: `MUT_EXIT=0` · 281 запись · 281 RED · выживших 0 · неизмеренных 0 · `anchors swept: 0 of 492 entr(ies) rotten`.** Вердиктов 281 против 281 записи в гейте — сверено числом, а не хвостом лога. - ⚠ **И это ТРЕТИЙ полный прогон; первые два итогом не стали, и оба раза по моей вине.** Первый дал `MUT_EXIT=2` — 278 RED и ДВЕ НЕИЗМЕРЕННЫЕ («nothing ran», обе не собирались; разобраны в таблице находок). Второй прошёл чисто, но приёмка нашла в коде асимметрию счётчиков, а третья её ось — отсутствие посадки под единственную денежную ручку, лендящуюся включённой; правка кода и правка каталога обесценили его числа. ⇒ каждый раз пере-гонялось ЦЕЛИКОМ, а не по затронутым записям. Прежняя редакция этой строки говорила «второй прогон» и была верна ровно до третьего круга приёмки. Он дал `MUT_EXIT=2`: 278 RED, 0 выживших и **2 НЕИЗМЕРЕННЫЕ** («nothing ran») — обе не собирались, обе разобраны в таблице находок выше (одну сломал мой рефактор, вторую я завела и не прогнала поодиночке). После починки прогон повторён ЦЕЛИКОМ, а не по затронутым записям: правка лежала в `stagerun.go`, которого касаются 14 записей каталога, значит прежние 278 сняты на другой редакции и итогом быть не могли. ##### Где мой прибор слеп, и я это знаю 1. ⛔ **КОД ВОЗВРАТА И УВЕДОМЛЕНИЕ НЕ ОТВЕЧАЮТ НА ВОПРОС «ЧТО СТАЛО С ПРЕДМЕТОМ» — НИ В ОДНУ СТОРОНУ.** За этот пак класс встретился трижды и каждый раз иначе: обёртка вернула **0** на кампании, которая упала (`MUT_EXIT=2`) · гейт упал с **2** при НУЛЕ строк `FAIL`, потому что до тестов не дошёл · перезапуск был **убит по памяти**, и уведомление пришло как «killed», то есть ни нулём, ни ненулём. Работает ровно одно: строка-итог из лога (`MAKE_EXIT` / `MUT_EXIT`) плюс сверка полноты СПИСКОМ. Если строки-итога в логе нет — прогон не закончился, чем бы ни было уведомление. 2. ⛔ **КОНТРОЛЬ «ВСЕ ЯКОРЯ РАЗРЕШАЮТСЯ» НЕ ВИДИТ ЗАПИСЬ, КОТОРАЯ ПЕРЕСТАЛА СОБИРАТЬСЯ.** Я гоняла его после каждой правки и считала достаточным. Он проверяет, что строка-цель НАЙДЕНА, а не что правка даёт собирающийся пакет — и обе мои неизмеренные записи проходили его зелёными. Отличает их ровно один прибор: полный прогон каталога, где несобирающаяся правка выходит отдельным исходом «nothing ran» (за что харнесcу отдельное спасибо — он НЕ читает ненулевой код возврата как поимку). 3. **Одиночная проба посадки спрашивает ОДИН тест.** Харнесс гоняет запись каталога с `-run <тест>`, поэтому «SURVIVED» при одиночной проверке значит «выжила против ЭТОГО теста», а не «дыра в пинах». Так я и получила ложное «no-op» про `retryable()`. ⇒ выжившую при одиночной пробе перепроверяю прогоном ВСЕГО пакета, прежде чем писать о ней что-либо в `why`. 4. **`go vet ./<пакет>` не компилирует файлы за билд-тегом.** Я меняла сигнатуру и проверяла пакет обычным `vet` — он был зелёным, пока гейт зоны не собрал тот же пакет с тегом `live` и не упал. ⚠ И форма падения ровно та, о которой предупреждает канон: `MAKE_EXIT=2` при НУЛЕ строк `FAIL` — «все тесты зелёные» было бы правдой, которая не значит ничего, потому что до тестов гейт не дошёл. Закрывается тем, что теперь я гоняю ОБА набора тегов; в отчёте это названо, а не спрятано. 5. **Пин шва видит только обычное написание вызова.** Обход ищет `CallExpr` с селектором `runAttempt`; метод-значение (`f := r.runAttempt; f(…)`) или вызов через интерфейс он пропустит. Денежный путь так случайно не пишут, поэтому обход всё равно стоит держать — но «нового вызывающего нет» здесь значит «нет вызывающего, написанного обычным способом». Названо в самом файле. 6. **Шов «усилие в допуске» почищен, но не запинен.** Ветвь понижения усилия недостижима на боевых настройках дважды: нужен `retries.lower_effort_on_empty` (выключен во всех боевых, пин есть) И ступень ниже настроенного усилия, а банк-роли настроены на `low` — дно лестницы `Models.ReducedEffort`. Посадка под этот шов сегодня ВЫЖИЛА БЫ, ничего не измерив, — поэтому записи каталога под него НЕ завожу (посадка обязана атаковать то, что стережёт пин). Условие достижимости названо в коде. 7. **Живой прогон не гонялся.** Всё снято на фикстурах; платных вызовов пак не делал. 8. **Эффект на КАЧЕСТВО перевода не измерен** — измерима только механика. Мерило эффекта, как и велит промт, журнал запросов боевого прогона (`asked`/`answered` по батчам), не проекция: у неотвеченного кандидата остаётся эвристический тип, и проекция покажет 66 из 66. ##### Адреса, которые съехали (оркестратору — сэкономить проход) ⛔ **ДВА ОПЕРАТОРСКИХ ПРЕДУПРЕЖДЕНИЯ ПЕРЕИМЕНОВАНЫ, И ЭТО НЕ СДВИГ СТРОК — прежняя редакция этого раздела называла только сдвиг, то есть отправляла чинить вслепую.** Петля стала общей для стадии и банк-роли, поэтому слово «stage» в её тексте перестало быть верным: | было (в `backend/` → 0 файлов) | стало (→ 1 файл кода + каталог) | |---|---| | `stage flagged, regenerating with a larger budget` | `the call was flagged, regenerating with a larger budget` | | `stage returned nothing at the full budget, regenerating with less thinking at the SAME budget` | `the call returned nothing at the full budget, regenerating with less thinking at the SAME budget` | ⚠ **Цена уже видна, и она не в моей зоне:** четыре живых адреса в доках ссылаются на СТАРЫЙ текст, и греп по нему теперь даёт ноль — `docs/architecture/05-decisions-log.md:2670` (там грепать эту строку ПРЕДПИСАНО), `docs/experiments/25-door-to-file-b.md:306`, `docs/experiments/24-door-to-file.md:233` и `:688`. Чинит оркестратор; моё дело было НАЗВАТЬ, и в первой редакции я этого не сделала. **Строки сдвинулись** в `backend/internal/pipeline/stagerun.go` (тело петли вынесено) и `backend/internal/pipeline/terminologist.go`; какие якоря реально уехали, судит гейт якорей. ⚠ **Число живых якорей я из отчёта убираю, потому что оно не восстанавливается без своей команды.** Мои «115 и 62» получаются так: `command grep -rn "<файл>:[0-9]" docs/ backend/docs/ --exclude-dir=prompts --exclude-dir=reports | wc -l`. Исключишь ещё `docs/archive/` — выйдет 53 и 51; приёмка своим способом получила 36 и 43. Все три счёта верны для своих соглашений, и ровно поэтому голое число здесь было бесполезно: отчёт обещает у каждого числа команду повторения, а у этого её не было. ##### Аддендум владельца 17.09 — исполнение по пунктам 1. **Тщательно проектируй.** Записка-план легла в этот журнал ДО первой правки движка. 2. **Комментарии без гарантий без пинов; вывод называет условие отмены.** Исполнено; мой собственный случай этого класса (ложно-зелёный голден) — в таблице находок. 3. **Прозы в коде нет** — комментарии объясняют «почему так», а не «что делает строка». 4. **Общность.** В лестнице нет ни одной ветки по паре или книге; порогов-констант в Go не заведено — единственная новая ручка (`regenerate`) это ДАННЫЕ конфига. 5. **Советчик.** Поднят один фабл с постоянным контекстом, на ПРОЕКТИРОВАНИИ (до банковой половины). Нашёл денежный дефект в моём же шве (находка 2) и отговорил от судьи аргументом, который я приняла. 6. **Греп по докам и полигону** — пользовалась: §4.3 и §4.4 закрыты чтением `25-door-to-file-b.md` и пина в `configs/models.yaml`. ##### Гейт зоны — цели пройдены, но НЕ формой `make battery` целиком, и я называю это точно ⛔ **`make battery` ЦЕЛИКОМ не отработал на этой машине: его убивал супервизор ФОНОВЫХ задач харнесса.** ⛔ **ИСПР. ПРИЁМКОЙ 17.09 — УТВЕРЖДЕНИЕ ВЫШЕ ОБОБЩАЕТ ШИРЕ ЗАМЕРА, и назвала это сама зона, уже после лендинга.** Верно: `make battery` целиком не отработал **В ФОНОВОЙ ЗАДАЧЕ ЭТОЙ СЕССИИ** (четыре попытки, включая одну на пустой машине). Неверно «на этой машине»: приёмка прогнала тот же гейт на копии той же редакции, ТОЖЕ В ФОНЕ, при `MemFree` **0.5 ГБ** на старте — и он прошёл целиком (`MAKE_EXIT=0`, 24 = 24, контроль с жертвой печатает 1). ⇒ **потолок фоновых задач НЕ ОДИНАКОВ У СЕССИЙ**, и «гейт не помещается в машину» неверно даже как описание. Прежняя формулировка оставлена видимой: замер зоны верен для её задачи, ошибочна была область действия вывода. ⚠ Остальное в разделе замер выдерживает (`archguard.test` 3.26 ГБ · `LoadAllSyntax` с `Tests: true` · порог по `MemFree`, а не `MemAvailable` · `memory.max = max` у обоих слайсов · A/B чистого `HEAD` против дерева +0.3 %). Носитель улики — ряд **488**. Не ядро по cgroup (`memory.max = max` у `tm.slice` и `tm-runs.slice`), не нехватка памяти у машины (`MemAvailable` держался 4–7 ГБ). Виновник назван прибором поимённо: **`archguard.test` растёт до 3.26 ГБ** (`internal/archguard/shippingtree_test.go:34` грузит ВЕСЬ модуль — `packages.LoadAllSyntax`, `Tests: true`), а супервизор бьёт по `MemFree`. Ряд **488**. **Как прогнано вместо этого — и почему это НЕ сужение гейта:** - `make build` · `make vet` · `make fmt` · `make lint` — как есть, целями Makefile, все четыре `ok` (линтер 0 issues); - тестовая цель — **ТЕМИ ЖЕ флагами** (`-race -count=1 -timeout=20m`), но по ОДНОМУ пакету из `go list ./...`; `-run` не применялся нигде; - `internal/archguard` — тот же пакет и те же флаги, но в ПЕРЕДНЕМ плане, где фоновый супервизор не действует: `ok 25.221s` (в отдельном замере пик **3 418 648 kB**, совпал с показанием семплера). ⚠ Форму «целиком» я пробовала ЧЕТЫРЕ раза, включая один раз на пустой машине, — убивало на одном и том же пакете. Пере-проверять пятый раз не стала: причина измерена и подтверждена трижды. ⚠ **Что при этом изменилось в приборе, а не только в расписании:** исчезла МЕЖПАКЕТНАЯ одновременность. Для теста, чувствительного к состоянию процесса или к соседям по машине, это другой предмет. Поэтому формулировка ровно такая: **цели гейта пройдены в этой форме; «`make battery` зелёный» я не утверждаю.** **Полнота — списком, с НАСТОЯЩЕЙ жертвой:** `go list ./...` даёт **24**, вердиктов **24**, `comm -23` пусто, **контроль с жертвой печатает 1**, не-`ok` вердиктов **0**; четыре дешёвые цели — `build` · `vet` · `fmt` · `lint` — прошли целями Makefile, линтер 0 issues. ⚠ Рядом напечатан и перевёрнутый порядок операндов — он даёт 0 ВСЕГДА и не доказывает ничего. ⚠ По дороге тот же гейт поймал мою ошибку: `MAKE_EXIT=2` при НУЛЕ строк `FAIL` — падение на `go vet -tags live`, до тестов дело не дошло. Вердикт читается строкой-итогом и списком целей, а не хвостом лога. ##### Числа и как их повторить Все числа сняты ПОСЛЕ последней правки дерева. | что | команда | |---|---| | гейт зоны целиком | `cd backend && make battery` — прошёл `MAKE_EXIT=0`, 24 пакета против 24 вердиктов, `comm -23` пуст, контроль с жертвой печатает 1 (вердикт — строка `MAKE_EXIT`, полнота — сверка списком, а не отсутствие слова FAIL) | | новые пины пака | `cd backend && go test ./internal/pipeline/ ./internal/config/ -count=1 -run 'TestBankBatchPurchaseKeyValueIsPinned\|TestTheBankPassBuysAtThePinnedKey\|TestATruncatedBankBatch\|TestAHealthyBankTable\|TestARungTheRoleBudget\|TestTheExtraRungIsBought\|TestAnAlreadyBoughtRung\|TestTheBankPassNamesItsAnswerShare\|TestOnlyTheLadder\|TestShippingPipelinesRegenerateBankRoles'` | | пре-существующие пины переехавшего механизма, под `-race` | `cd backend && go test ./internal/pipeline/ -race -count=1 -run 'TestABurnFollowedByARegenerationDoesNotOverBuy\|TestEchoRegen\|TestTheRetryForAnEmptyReplyBuysLessThinkingNotMoreBudget\|TestGoldenDeterminism'` | | каталог мутаций, батарейное подмножество | `cd backend && make mutations` | | целостность каталога (все правки разрешаются уникально) | `python3 -c "import json;ms=json.load(open('backend/cmd/tmmutate/mutations.json'));print(sum(len(m['edits']) for m in ms), sum(1 for m in ms for e in m['edits'] if open('backend/'+e['file']).read().count(e['find'])!=1))"` | | ⚠ гейт гонять, когда на машине нет другого тяжёлого прогона | ⛔ **ПРИЧИНА ИЗМЕРЕНА, а не выведена, и три моих версии до неё оказались ложными.** Гейт убивало трижды; я думала на конкуренцию наборов (умерло: убило в одиночку), на параллелизм пакетов (умерло: убило с `-p=2`) и на тяжесть `internal/pipeline` (умерло замером: **313 МБ** пик под `-race`). Прибор с семплером назвал виновника поимённо: **`archguard.test` растёт монотонно до 3.2 ГБ** — `internal/archguard/shippingtree_test.go:34` грузит ВЕСЬ модуль (`packages.LoadAllSyntax`, `Tests: true`), то есть его память пропорциональна размеру репозитория. Это НЕ потолок cgroup (`memory.max = max` у `tm.slice` и `tm-runs.slice`) и не нехватка памяти у машины (`MemAvailable` держался ≈4.2 ГБ): падает `MemFree` (до 110 МБ), и супервизор бьёт по нему. ⇒ гейт проходит, когда рядом не идёт второй тяжёлый прогон; резать его через `-run` не понадобилось. ⭐ **И это НЕ мой пак:** A/B тем же тестом и теми же флагами — чистый `HEAD` (развёрнут `git archive`) **1.44 ГБ**, рабочее дерево **1.44 ГБ**, разница **+0.3 %** (+3.8 МБ на ≈1460 добавленных строк тестов, которые `Tests: true` тоже грузит). Нагрузка пред-существует паку и растёт с размером РЕПОЗИТОРИЯ, а не с моей правкой. ⚠ Контроль этого замера тоже стоит назвать: первая попытка шла с `-run TestShipping`, вернула `ok … [no tests to run]` и 126 МБ — то есть «дешёвый базис», которого не было. Настоящее имя `TestInvariantsHoldInTheShippingTree`. Прими я тот ноль за базу — «пак утроил память» вышло бы из контроля, который не запускался | | замер §4.4 (сдвиг ординала) | `cd backend && TM_PROBE_478=1 go test ./internal/pipeline/ -run TestProbeBankBatchOrdinalShift -v` (по умолчанию скипается; печатает знаменатели и положительный контроль) | ##### Опись путей, передаваемых оркестратору (18) **Изменено (12):** `backend/cmd/tmmutate/mutations.json` · `backend/configs/pipeline-c1.yaml` · `backend/configs/pipeline-arm-glm.yaml` · `backend/configs/pipeline-arm-mistral.yaml` · `backend/internal/config/pipeline.go` · `backend/internal/pipeline/stagerun.go` · `backend/internal/pipeline/terminologist.go` · `backend/internal/pipeline/live_reprobe_test.go` · `backend/internal/pipeline/miningstop_join_test.go` · `backend/internal/pipeline/testdata/operator-messages.txt` · `backend/internal/pipeline/runner_test.go` · `docs/PROGRESS.md`. **Новое (6):** `backend/internal/pipeline/attemptladder.go` · `backend/internal/pipeline/attemptladder_seam_test.go` · `backend/internal/pipeline/bankkeygolden_test.go` · `backend/internal/pipeline/bankladder_test.go` · `backend/internal/pipeline/bankbatchordinal_probe_test.go` · `backend/internal/config/bankregenerate_shipping_test.go`. ⚠ Ничего за пределами `backend/` и своей секции этого журнала не тронуто; параллельные правки платформенной зоны в дереве я не касалась. ##### Завершённость - у каждого пункта заказа есть исход (таблица в начале): сделано · не делаю с доводом · снято оркестратором; - круги сошлись — последний адверсариальный проход не дал новых находок, прежние закрыты таблицей «находка → что сделано → чем предъявлено»; - таблица мутаций полная; **выживших нет ни одной**, а обе выжившие промежуточных кругов были МОИ мис-посадки, а не дыры в пинах, и обе разобраны поимённо; **полный прогон батарейного подмножества каталога пройден числом — 280/280 RED при `MUT_EXIT=0`**; - список «что отрефакторено и почему» — в разделе «Разрез»; - всё живое — в дереве, ничего не осталось в скретчпаде; - **работа завершена, править не планирую.** Гейт и кампания сняты на ТОМ ЖЕ дереве, которое передаётся: после последней правки дерево не менялось (18 путей описи до прогонов и после). #### ЗАПИСКА-ПЛАН пака «ЛЕСТНИЦА ПОПЫТКИ ДЛЯ БАНК-РОЛЕЙ» (17.09, сессия `textmachine-main-12`). До первой правки движка. НЕ КОММИЧУ **Предмет, пере-снятый по дереву, а не по промту.** Банк-роли зовут `runAttempt` напрямую (`terminologist.go:861`, попытка 0, фиксированный потолок) и читают из результата ТОЛЬКО текст (`terminologist.go:1055`). Вердикт `att.cls`, который `classifyOutput` уже посчитал внутри `runAttempt`, не читает ни одна ветка. Лестницы нет: один вызов, один потолок, тишина. **Почему лекарство именно «больше потолок».** По прогону B (`docs/experiments/25-door-to-file-b.md` §7): `batch=0 asked=22 answered=4` (`length`) и `batch=2 asked=24 answered=0` (`empty`), оба оплачены. Причина названа там же и в `configs/models.yaml`: у DeepSeek размышление считается ВНУТРИ `completion_tokens`, и у всех семи выброшенных вызовов оно съело ПОЛНЫЙ потолок (8496/8496 ×3, 8000/8000, …). Хоп на другую модель такого не лечит; лечит удвоение бюджета — на черновой стадии того же прогона оно вылечило 5 из 5. Там же ратифицирована экономика: **перебор бюджета бесплатен (резервация транзитна, списание по факту), недобор стоит ЦЕЛОЙ генерации.** Бюджет фазы при этом не был ограничителем: лимит $1.00, потрачено $0.029749. ##### Разрез Цикл попытки из `runStage` (`stagerun.go:197–268`) переезжает в отдельную функцию с ДВУМЯ вызывающими. `runStage` = резюм по `chunk_status` + лестница + эскалация + диспозиция; банк-роль = лестница + разбор таблицы. `runStage` из терминолога НЕ зовётся: у банк-батча нет ни чанка, ни строки статуса, ни шаблона. **Три параметра, и все три несущие:** | параметр | у стадии | у банк-роли | |---|---|---| | ключ ступени | число УДВОЕНИЙ (`maxTokensForAttempt(base, escalations)`) | то же самое, один перечислитель | | допуск ступени | счётчик регенераций (`regenerate_before_escalate`); книжный потолок живёт в резервации | счётчик + **ролевой суб-бюджет**, иначе §4.2 | | судья ступени | `classifyOutput` внутри попытки | он же ПЛЮС вердикт после разбора таблицы | ⛔ **Ступень ключуется числом удвоений, а НЕ номером попытки.** `attempt` считает КЛЮЧИ и перешагивает сожжённые (walk по `burnedByCut`), `escalations` считает деньги; в `RequestHash` они входят РАЗНЫМИ полями (`Attempt` и `MaxTokens`). Подмена одного другим — смена ключа покупки. ##### Прибор построен ПЕРВЫМ, до выноса `backend/internal/pipeline/bankkeygolden_test.go` — голден ЗНАЧЕНИЯ хеша банк-батча. Привязан к ФИКСТУРЕ (книга, снапшот, модель, усилие, сообщения, пол `min_max_tokens` заданы самим тестом), а не к боевому конфигу: голден на боевом краснел бы от пере-пина цены или правки промта, то есть от вещей, к ключу отношения не имеющих, и его начали бы обновлять не глядя. Два слоя: чистая деривация через продакшн-шов и **исполнение** — реальный проход `runBankRoleBatches` покупает, и хеш читается из хранилища. ⛔ **Первая редакция голдена была ложно-зелёной, и это найдено посадкой, а не глазом.** Сообщения были короткими, потолок упирался в `MinMaxTokens=512`, и вся арифметическая ветвь формулы `est/2 + floor` в ключ не входила: сдвиг `terminologyReplyFloor` 256→257 оставлял файл ЗЕЛЁНЫМ. Чинится тем, что батч 0 сидит В полу, а батч 1 его перерастает, и **посылка утверждается внутри теста** — иначе фикстура тихо съедет обратно в один режим. Посадки после починки: `attempt 0→1` RED · ординал `i→i+1` RED · пол 256→257 RED · формула `est/2→est/3` RED · роль выпала из `bankStage` RED · температура в `InternalCall` RED (по посылке). Копия для посадок — `/home/ubuntu/tm-bankladder-mut`, вне скретчпада; после каждой цели проверено, что ЦЕЛЬ на месте, и `diff -rq` против живого дерева даёт 0 расхождений. ##### Эскалация банк-ролей (§4.3) — НЕ строю, и вот что защищает нулевой хоп Прочитал `internal_call.go` и `escalation.go`. Комментарий защищает не одну вещь, а пять, и они разного рода: 1. **Чужой пул.** `escalationBudgetRemains` читает `Pipeline.Escal.BudgetUSD` и `EscalationSpentUSD(книга)` — пул КНИГО-ШИРОКИЙ и принадлежит волне. Банк-хоп ел бы его молча. 2. **Способ деградации.** «these calls degrade by leaving their work unchanged rather than by paying a second model»: неотвеченный терм остаётся `auto` и ничего не портит, в отличие от чанка, который отгрузил бы брак. 3. **Предварительная сборка клиентов.** `gateModels()` кладёт в достижимые модели только модели ВКЛЮЧЁННЫХ гейтов; модель хопа туда не попадает — и `buildClients`/`CheckKeys` пропустят её, а прогон умрёт на банк-стопе «no pre-built client» ПОСЛЕ оплаченной волны. Это уже случалось (комментарий `gateModels`). 4. **Аддитивный буфер.** `InternalCall` держит `ReasoningMaxTokens: 0`, и это безопасно лишь потому, что загрузчик ОТКАЗЫВАЕТ аддитивному провайдеру для моделей гейтов. Модель хопа потребовала бы того же отказа. 5. **Имя отказа в стоп-марке.** `ceilingStopDetail` (`cutcall.go`) утверждает, что отказ потолка называет РЕ-АТАКУ, и это верно, пока каждый прочий платный шаг ловит `errReserveCeiling` и деградирует. ⇒ **Хоп не строю, и довод не «дорого», а «не то лекарство»:** измеренная болезнь — размышление, съевшее потолок; другая модель потолка не лечит. Лестница (мой предмет) лечит ровно её. Класс, для которого хоп осмыслен, — `refusal` (тот же вызов на той же модели пере-откажет, D2.2) — на банк-ролях имеет замеренную популяцию ноль. Если владелец захочет хоп, пять пунктов выше — его спецификация, и они уходят в отчёт. ##### Тождество банк-батча (§4.4) — развилку НЕ беру, потому что ПОСЫЛКА РЯДА 478 НЕ ПОДТВЕРЖДАЕТСЯ Ряд 478 утверждает: «снимет фильтр одну решённую строку — номера всех последующих батчей сдвигаются, и они покупаются заново при неизменном тексте». Пере-мерил на настоящем `terminology.Batch`. **Механика.** Упаковка жадная. Снятие кандидата из батча k либо ПОДТЯГИВАЕТ содержимое из k+1 (тогда у всех последующих меняется ТЕКСТ, и ординал ни при чём), либо не подтягивает (тогда у них не меняется ничего — ни текст, ни номер). Сдвиг номера при неизменном тексте требует, чтобы батч исчез ЦЕЛИКОМ из середины. **Числа.** Снятие ОДНОГО кандидата, 246 снятий в четырёх режимах: сдвинутых-с-тем-же-текстом **0** (при живых `content-changed` 239…630 — прибор различает классы). Снятие БЛОКА (как и работает `dropBankSettled` — он снимает множество), по 200 случайных блоков на режим: | режим | батчей | сдвинуто с тем же текстом | |---|---|---| | `batch_runes=400`, 60 кандидатов | 19 | **475** | | `batch_runes=6000`, 66 кандидатов (боевой) | 2 | **0** | | `batch_runes=6000`, 300 кандидатов (боевой) | 6 | **0** | Положительный контроль: убрать батч 1 целиком — прибор показывает **18 сдвигов из 19**, то есть ноль выше не слепота прибора. **Боевой режим — это вторая и третья строки:** `batch_runes` не задан ни в одном из трёх боевых конфигов, значит работает движковый умолчательный 6000; на прогоне B это дало 3 батча на 66 термов (22 · 19 · 24). ⇒ **Ключ не трогаю.** Не потому, что дорого, а потому, что механизм ряда 478 в боевом режиме имеет популяцию ноль, а обе ветви стоят одноразовой пере-чеканки ВСЕХ банк-чекпойнтов. ⚠ **Условие, при котором вывод перестаёт держаться, называю сразу:** мелкий `batch_runes` (сотни рун) делает класс живым — 475 на 200 снятий. Ряд 478 остаётся открытым с этим замером и этим условием; доминирующий драйвер пере-покупки — пере-упаковка СОДЕРЖИМОГО — ни одной из двух ветвей не лечится и назван ограничением в самом `dropBankSettled` («a checkpoint identity that survives a change of batch composition … belongs in its own decision»). ##### Что ещё в заказе - **§4.2** — допуск и проба обязаны говорить об одних ступенях: сегодня проба `bankCheckpointExists` спрашивает только попытку 0 (`terminologist.go:840`), а суб-бюджет считается только по неоплаченным батчам. Ступени лестницы уйдут мимо бюджета фазы — это чиню вместе с лестницей. - **§4.5** — доля ответов: поднимаю СУЩЕСТВУЮЩИЙ построчный счётчик до итога и развожу его с числом батчей, выброшенных бюджетом; третьего счётчика не завожу. #### ОТЧЁТ пака «БАНК — ЧТО МОЖНО УЗНАТЬ И ПОЧИНИТЬ ЗА $0» (16.09, сессия `textmachine-main-11`). НЕ КОММИЧУ — дерево передаю оркестратору №23 **Деньги пака: $0.** Платных вызовов моделей не было ни одного. Все числа сняты по уже купленному сырью прогонов A и B, открытому только на чтение и только с КОПИЙ в скретчпаде. ##### Что построено — по пунктам заказа | пункт | исход | чем предъявлено | |---|---|---| | §4.1 громкий отказ, когда у ЦЕЛИ нет строк инъекции | сделано, и ШИРЕ заказа: арм пять, а не три | `backend/internal/pipeline/injectionpreflight.go:96`=`func (r *Runner) checkInjectionTexts` + вызов `backend/internal/pipeline/runner.go:389`=`if err := r.checkInjectionTexts(logger); err != nil {` рядом с соседним отказом `:364`=`if forWrite && r.Pipeline.Gates.Terminology.Enabled && r.pack == nil {`; пин `TestABankItsTargetCannotStateRefusesBeforeItIsBought` (6 подтестов) | | §4.1 предикат ПОЛНОТЫ, а не заголовка | сделано | `lang.InjectionTexts.MissingKeys` / `Authored` / `GenderKeyGaps` + реестр `roleInjectionKeys` (`chunkrun.go`); пины `TestTheInjectionKeysAreOneVocabulary`, `TestAPartialInjectionSetIsVisibleToTheGuard` | | §4.2 отказ роли перестаёт быть передачей (путь **а**) | сделано; сентинел НЕ тронут | `terminology.go` — ветвь `declined` рядом с `isNoDst`; пин `TestAProseDeclineLandsInTheDeclineBucketAndNotInTheBank` | | §4.2 мусор разведён с отказом по корзинам | сделано | ветвь `hasLetter` + счётчики `NoLetters`/`DeclinedByPhrase`; пины `TestARenderingWithNoLettersReadsAsUnansweredNotAsCanon` (парсер) и `TestADeclineAndGarbageLandInDifferentBuckets` (сквозной, все три исхода в одном ответе) | | §4.2 реестр фраз — ДАННЫЕ, лендится пустым и запинен пустым | сделано, плоскость выбрана иначе — см. «Отклонения» | `backend/internal/lang/bankdata/decline-phrases.txt` + `declinephrases.go`; пины `TestTheDeclineRegistryShipsEmpty`, `TestTheDeclineMatchIsTheWholeFieldAndFoldsTheShapesAModelWrites`, `TestAProseDeclineNeverBecomesTheBooksCanon` (проводка) | | §4.3 ДВА предиката | сделано | pre-call `terminology.Candidate.Contest` (`contested.go`), post-call `pipeline.BankStopRow.Contest` (`stopcontest.go`) | | §4.3 $0-харнесс реплея | сделано | `backend/cmd/tmbankprobe/` + движковый ридер таблицы стопа `pipeline.ParseBankStopTable` с раунд-трип пином | | §4.3 таблица чувствительности на обоих источниках с обоими знаменателями | сделано | числа ниже; знаменатели напечатаны с компонентами | | §4.4 носитель для «новой улики не было» | **ответилось ЧИСЛОМ**, а не «данных нет» | режим `-passes` того же харнесса | | мутации новых мест | 37 записей, каталог 441 → 478, все помечены `battery` | `cmd/tmmutate/mutations.json` | ##### §4.1 — что именно стережёт отказ, и почему условие ШИРЕ промта **Предмет:** у цели без строк инъекции оба банк-блока рендерятся в НОЛЬ БАЙТ без ошибки (`membank.RenderGlossaryBlock`/`RenderEditorConstraintBlock` гейтятся на `HasData()`, а `lang.InjectionTextsFor` возвращает нулевое значение для незнакомой цели молча). Отказ стоит в `openRunner`, формой `RefusalBadConfig`, **до открытия волн и до первого платного вызова**, и только на пути записи — `$0`-чтение книги остаётся возможным (D20.4, запинено отдельной веткой). ⛔ **Арм, по которым строки попадают в банк, ПЯТЬ, а промт называл три.** Инъекция строится при `r.baseMemory != nil`, то есть мимо гейтов: 1. `gates.terminology` — роль консолидирует строки на этом прогоне; 2. `gates.banknote` — черновик спрашивается о таблице терминов; 3. `book.yaml glossary_seed` — сид; 4. **`.mined-delta.yaml`** — подписанные владельцем строки. ⚠ Путь ДЕРИВИРУЕТСЯ (`backend/internal/config/book.go:210`=`b.MinedDelta = filepath.Join(dir, b.BookID+MinedDeltaSuffix)`), поэтому `book.MinedDelta != ""` истинно ВСЕГДА и как арм негоден — проверяется НАЛИЧИЕ файла (`decisionFilePresent`); 5. **авто-банк, оставленный в сторе предыдущим прогоном** (`backend/internal/pipeline/mining.go:723`=`func (r *Runner) loadAutoBank`). Гейт — ран-локальный конфиг книги (`D39.126` п.2а), а строки в сторе — нет: книга с выключенными гейтами, без сида и с банком от прошлого прогона инжектит так же молча. Армы спрашиваются в порядке цены (`backend/internal/pipeline/injectionpreflight.go:40`=`func (r *Runner) bankRowsReachTheWire`): два поля конфига → один `stat` → чтение стора, и стор трогается только когда всё дешёвое сказало «нет». **Ошибка чтения дверью не считается** — WARN и «строк нет», по норме «предупреждение о деньгах не выдумывается из ошибки». **Полнота набора текстов — только по РЕНДЕРЯЩИМСЯ ключам, и вот какие вошли:** `glossary_header` (блок переводчика) и `editor_header` (блок редактора) — по одному на роль, через реестр `roleInjectionKeys`, стоящий рядом с реестром рендереров. **Не вошли:** `editor_unverified_header` и `unverified_marker` — ОТСТАВЛЕНЫ (`D39.104` п.2, ряд 134), их никто не рендерит, и требовать их значило бы заставлять новую пару заполнять мёртвый текст (ключи сделаны неэкспортируемыми, чтобы гард снаружи не смог их назвать). **Гендерные директивы не требуются** — цель без грамматического рода законно не пишет ни одной, и её строки обязаны рендериться без директивы; но ПОЛОВИНЧАТЫЙ набор (есть `gender_male`, нет `gender_hidden`) — это ошибка авторства, и на неё стоит WARN с перечнем недостающих ключей: механизм работает, теряется только формулировка владельца (`D39.254` п.3). **Пин краснеет на ДАННЫХ, а не на отказе соседа:** фикстура строит синтетическую пару zh→xx (реальный zh-источник langpack-а, каталог пары — копия zh-ru, промты пары на месте), и ПЕРЕД мутацией та же книга открывается на запись — то есть загрузчик и соседний отказ `:356` пройдены. Четыре двери, доступные фикстуре (гейт терминологии · гейт банкноты · сид · мината-дельта · строки в сторе — пять подтестов, в каждом открыта ровно ОДНА); плюс негатив «книга без банка вовсе НЕ отказывается» (иначе условие выродилось бы в «у цели нет текстов») и ветка `$0`-чтения. ##### §4.2 — разбор ужесточён, корзины разведены - **Отказ прозой** → та же корзина, что у сентинела: ключ присутствует с ПУСТОЙ передачей ⇒ `Declined` (плюс счётчик `DeclinedByPhrase`, потому что «роль отказалась словами» — это про ПРОМТ пары, и об этом иначе не узнать). - **Мусор — `dst` без букв ВООБЩЕ** («90», `——`) → плохая строка, ключа в ответе нет ⇒ `Unanswered` (плюс счётчик `NoLetters` и до восьми строк ОБРАЗЦАМИ). ⚠ Критерий — отсутствие БУКВ, а не наличие цифр: «Отряд 731» остаётся (контроль в пине). Направление ошибки объявлено в коде. - ⚠ **Порядок проверок несущий, и фикстура это утверждает:** односимвольный мусор («…») отбивается РАНЬШЕ, минимальной длиной `wellFormedLemma`, поэтому пин использует ДВУхсимвольный — иначе он краснел бы и с удалённой веткой, то есть удовлетворялся бы чужой уликой. - **Реестр отказных фраз** лендится ПУСТЫМ: в боевом файле **0 строк данных при 26 строках файла** (прибор — `grep -vc '^#\|^$'`, знаменатель напечатан), и пустоту стережёт пин **`TestTheDeclineRegistryShipsEmpty`** (`internal/lang/declinephrases_test.go`). Он утверждает три вещи разом: реестр парсится, в нём ноль языков, и файл ПРОЧИТАН (контроль по длине и по опорной строке) — «ноль строк» и «нет файла» здесь не путаются. ⛔ **Условие, при котором вывод перестаёт держаться, названо в самом пине:** реестр пуст, пока популяция отказов прозой не ИЗМЕРЕНА на купленном сырье (сегодня она ноль: 0 из 69 и 0 из 66 при контроле 69/69 и 66/66); появится замер — строка реестра и этот пин меняются ОДНОЙ правкой, и правка цитирует замер. Мутация `BANK-decline-registry-ships-a-phrase` сажает ru-фразу В ДАННЫЕ (не в Go — предмет пина тот же слой, что предмет посадки) и краснеет именно этим пином. Совпадение — СТРОГОЕ, по всему полю после свёртки (пробелы, кавычки любой формы, хвостовая пунктуация, регистр), и «клан, а не термин родства» остаётся передачей. Довод денежный: ложный отказ выбрасывает из банка строку, за которую книга ЗАПЛАТИЛА, а ретрая у банк-ролей нет вовсе (ряд 438). - **Проводка запинена отдельно:** открытый раннер обязан нести предикат (`r.declinedByPhrase != nil`), потому что «реестр пуст» и «роль не получила реестра» на пустом реестре ведут себя ОДИНАКОВО, а состояния это разные — одно решение, другое незаметный баг. - **Перекупки правка не вызывает:** парсер в тождество запроса (`attemptRequest`) не входит. Меняется СОДЕРЖИМОЕ банка ⇒ `memory_version` ⇒ пере-редактура под обычным согласием. Это записано в комментарии у самого файла данных. ##### §4.3 — два предиката и таблица чувствительности **Пороги в Go не зашиты ни одним значением.** У обоих предикатов — структуры входов без умолчаний; единственный сегодняшний вызывающий — $0-харнесс, который варьирует их по сетке. Платного потребителя нет НАМЕРЕННО: маршрутизировать по неизмеренному признаку запрещает сам пак. **Знаменатели (заданы промтом, напечатаны с компонентами):** pre-call — кандидаты на входе роли; post-call — строки, на которые роль ОТВЕТИЛА. На этом сырье они СОВПАДАЮТ, и видно почему: `settled 0 · unresolved 0`. ⛔ **Расхождение 67/66 и 70/69 объяснено, и оно не про кандидатов:** лишняя строка в `bank_stop_presented` — АЛИАС `方源的`. Таблица пишется `presentedSurfaces` = src + ВСЕ алиасы кластера (`mining.go`), то есть это множество ПОВЕРХНОСТЕЙ, а не кандидатов, и знаменателем кандидатов быть не может. Одна и та же лишняя строка на обоих прогонах. | порог (pre-call, знаменатель — кандидаты на входе роли) | A-покупка 1 | A-покупка 2 | B-покупка 1 | B-покупка 2 | |---|---|---|---|---| | conventions ≥ 2 | 9/69 = 13.0 % | 9/68 = 13.2 % | 8/66 = 12.1 % | 8/65 = 12.3 % | | conventions ≥ 2, доля лидера ≤ 0.50 | 8/69 = 11.6 % | 8/68 = 11.8 % | 8/66 = 12.1 % | 8/65 = 12.3 % | | conventions ≥ 3 | 3/69 = 4.3 % | 3/68 = 4.4 % | 4/66 = 6.1 % | 4/65 = 6.2 % | | conventions ≥ 4 | 0/69 = 0 % | 0/68 = 0 % | 1/66 = 1.5 % | 1/65 = 1.5 % | | «не поддержан» (черновики не дали НИ ОДНОЙ передачи) | 0 | 0 | 0 | 0 | ⚠ **Знаменатель второй покупки на единицу меньше первой, и это не опечатка:** строка, которую банк РЕШИЛ (`NOT ASKED`), до роли не доходит — фильтр решённых стоит перед первым платным вызовом, — поэтому она не входит НИ в pre-call, ни в post-call знаменатель. Первая версия моего харнесса держала её в pre-call и выбрасывала из post-call: два знаменателя расходились на строку, не дошедшую ни туда, ни сюда, и каждая доля слева была тихо разбавлена. Исправлено, числа выше — после исправления. ⚠ **Арм доминирования на этом сырье почти инертен, и это свойство СЫРЬЯ:** у мульти-конвенционных строк почти везде по одному чанку на вариант, то есть ничья; порог 0.50 двигает A с 9 на 8 и B не двигает вовсе. Значит на этой книге «спорный» определяется ОДНИМ числом — количеством конвенций. | сигнал (post-call, знаменатель — строки, на которые роль ОТВЕТИЛА) | A-1 | A-2 | B-1 | B-2 | |---|---|---|---|---| | нет передачи (unresolved) | 0/69 | 0/68 | 0/66 | 0/65 | | конфликты (`CONTRADICTS` / банк уже держит) | 0/69 | 0/68 | 0/66 | 0/65 | | `invented` (передачи не было среди черновиков) | 11/69 = 15.9 % | 14/68 = 20.6 % | 17/66 = 25.8 % | 16/65 = 24.6 % | | `conf ≤ 60` | 12/69 = 17.4 % | 11/68 = 16.2 % | 14/66 = 21.2 % | 14/65 = 21.5 % | | `conf ≤ 70` | 27/69 = 39.1 % | 28/68 = 41.2 % | 25/66 = 37.9 % | 27/65 = 41.5 % | | `conf ≤ 70` + `invented` | 28/69 = 40.6 % | 30/68 = 44.1 % | 28/66 = 42.4 % | 29/65 = 44.6 % | | `conf ≤ 70` + `invented` + конфликты + unresolved | 28/69 = 40.6 % | 30/68 = 44.1 % | 28/66 = 42.4 % | 29/65 = 44.6 % | **Выбранное число И ЕСТЬ ответ на «сколько строк ушло бы на второй вызов».** ⛔ **Предикат, построенный на конфликтах, на этом сырье проверить НЕЛЬЗЯ** — их популяция ноль, и это сказано прямо, а не выдано за замер. Контроль напечатан: `invented` виден в 11 и 17 записях, значит прибор omitempty-поля ВИДИТ. ⚠ **Граница числа уверенности соблюдена и названа в коде:** `D39.102` п.2 ратифицирует `conf` как ordinal-очередь ревью ВНУТРИ одной модели. Порог здесь решает, КОГО посмотреть ещё раз, и ничего не весит; выбирать им передачу или сравнивать двух моделей код не может и не делает. ##### §4.4 — посылка «новой улики не было» получила носитель, и число сошлось с ратифицированным **Прибор:** разбор ДВУХ таблиц стопа одной книги (`project.db.bank-stop.txt` первой и второй покупки) движковым ридером, соединение по поверхности, сравнение ВХОДА строки (тип, канал, частота, предложения черновиков с числом чанков, улики миньера, **окна KWIC**) — и никогда ответа. - A: сменили передачу **12**; из них вход был байт-идентичен у **11**. - B: сменили передачу **14**; из них вход был байт-идентичен у **14**. - ⛔ **ПОПРАВКА 16.09 (нашла приёмка, я подтверждаю): знаменатель у этих долей был НЕ ТОТ.** Прибор печатал «12 из 69» и «14 из 66», а из ЧИСЛИТЕЛЯ строка, решённая банком, исключена — значит и в знаменателе её быть не должно: верно **12 из 68** и **14 из 65**. Класс тот же, что у арма `unresolved` в пост-колл-сетке (ряд 462): доля считается по популяции, из которой её же предмет вычтен. Сами числа смен и совпадений (12 · 11 · 14 · 14, итог 25 из 26) от этого не двигаются — двигается только доля. - Итого **25 из 26** — ровно число `research/35` §П1, снятое НЕЗАВИСИМЫМ методом, который вдобавок видит окна KWIC (метод K1 по `note` их не видел вовсе). - Единственное исключение названо: `宗祖祠堂` у A — сменился ТИП (`place` → `term`), то есть уехал классификатор, а не улика черновиков. - ⛔ **Из счёта смен исключены строки, которых вторая покупка НЕ СПРАШИВАЛА** (`NOT ASKED`): в обоих прогонах это `方源`. Его «смена» — артефакт того, что банк его решил, а не пере-решение; засчитав его, я бы раздула ровно то число, из которого считается экономика. - **Что сменилось на самом деле, проверено:** между покупками в обоих прогонах подписаны РОВНО ДВЕ строки (`方源`, `古月山寨`), то есть уехали якорь подписи и состав батчей — при неизменном блоке каждой строки. **Чего в сырье нет и почему вопрос закрыт не полностью:** тела запросов не хранятся нигде (`LOG_LLM_BODIES=1` пишет их ТОЛЬКО в лог и только на `LOG_LEVEL=debug`, обрезая до 32 КБ), а СОСТАВ батча и содержимое ЯКОРЯ не сохраняются вообще. Значит «якорь против стохастики модели» по-прежнему не разделено — ровно как и говорил `research/35`. **Дизайн персистенции (предложение, $0 в производстве):** хранить не тела, а **состав батча** — упорядоченный список ключей кандидатов — и **строки якоря**, которые для этого батча собрал `CanonFor`, ключом на `(book_id, snapshot_id, batch_idx, request_hash)`, рядом с `request_log`. Это байты на покупку, строится в момент `terminologyMessages`, тождество запроса не трогает и отвечает на оставшийся вопрос ТОЧНО: если состав и якорь совпали, а ответ другой — это стохастика модели, и больше ничего. ##### Чем проверено — команды, которые можно повторить - Пины и гейт зоны: `cd backend && make battery` (цель `battery` = `build vet fmt lint test`, `-race`). - Мутации: `go run ./cmd/tmmutate -root <КОПИЯ> -id <список>` — 37 новых записей, по одному прогону на запись; полное подмножество — `-battery`. - Замеры: `go run ./cmd/tmbankprobe -sheet A-pass1=<...bank-stop.txt> … -db … -passes A=<первая>,<вторая>`. - Базы читались ТОЛЬКО с копий, `mode=ro&immutable=1`; оригиналы не тронуты (mtime всех трёх файлов — 15.09, прежний). ##### Отклонения от буквы промта — три, каждое с доводом 1. **Реестр отказных фраз — в bankdata-плоскости движка, а не в langpack.** Langpack резолвится ПО КНИГЕ из `langpack_root`, и книга вправе не иметь его вовсе (золотой ja→ru гоняется без пака) — тогда один и тот же ответ модели читался бы двумя способами в зависимости от пути в `book.yaml`. Тем же доводом в дереве обоснован эмбеддед-блэклист провайдерских отказов (`internal/lang/data/refusal.txt`). Плоскость bankdata, а не `data/`, потому что `data/` складывается в `EmbeddedVersion`, который едет внутри каждого unit id: правка реестра пере-чеканила бы id всех книг, а разбор ответа не меняет ни байта ни одного запроса. 2. **Условие §4.1 расширено с трёх дверей до пяти арм** (гейты ×2, сид, мината-дельта, строки в сторе) — см. выше. 3. **§4.1 судит полноту набора, а не заголовок** — по прямому ответу оркестратора, и только по рендерящимся ключам. ##### §10 — что НЕ удалось и чего я не проверяла 1. ⛔ **Отказ прозой на настоящем сырье проверить НЕЛЬЗЯ, и это цена пустого реестра.** Сквозной пин работает на подменённом предикате; на боевых данных механизм инертен до первой авторской фразы. Пока фразы нет, ряд 445 закрыт ПОЛОВИНОЙ: мусор ловится всегда, отказ прозой — нет. 2. **Популяция мусора на купленном сырье — НОЛЬ** (0 из 69 и 0 из 66; контроль: буквы есть у 69/69 и 66/66). Пин по необходимости синтетический, и это назвать обязательно: замером на сырье он не является. 3. **Половинчатый набор текстов инъекции сквозным пином не покрыт.** В эмбеддед-данных ровно одна цель (`ru`); синтетическая вторая пере-чеканила бы unit id каждой книги. Предикат запинен на байтах в `internal/lang`, проводка — на цели БЕЗ строк вовсе. 4. **Я не пере-майнила книгу.** Кандидаты §4.3 восстановлены из проекции стопа — собственной записи движка о том моменте; настоящий реплей потребовал бы книги, langpack-а версии фриза и базы, которую движок открыть не может (см. п. 5). 5. ⛔ **База прогона A стоит на схеме 16 при голове 18.** Следствие проверено чтением: `store.OpenReadOnly` при `current != len(migrations)` ОТКАЗЫВАЕТ, а `store.Open` при `current < len(migrations)` МИГРИРУЕТ. То есть реплей через движковый стор по этой улике не «рискован», а невозможен без переписывания схемы купленного прогона. ⚠ **И отдельно, почему `immutable=1` ОБЯЗАТЕЛЕН, а не желателен:** обычный `mode=ro` НЕ бесследен — он создаёт/обновляет рядом с уликой файл `-shm`. Замерено на себе: первый мой зонд по `A-after` оставил `project.db-shm` с сегодняшним временем при БД, чьё `mtime` осталось 15.09. Байты базы не изменились ни у одной из трёх, но каталог улики был тронут, и только `immutable=1` этого не делает. Дисциплина (утверждена оркестратором как норма зоны): улики платных прогонов копируются в скретчпад, читаются своим ридером на `mode=ro&immutable=1`, хеши копий печатаются. 6. **Пост-колл предикат на конфликтах непроверяем на этом сырье** (популяция ноль на обоих прогонах, при непустых листах 660 и 648 строк). 7. **Денег второго вызова я не считала** — харнесс даёт число СТРОК, а не сумму: цена зависит от модели и упаковки батчей, а это решение следующего пака. 8. **Режим `-compare` (A↔B, два РАЗНЫХ прогона) даёт числа о другом предмете** — там черновики покупаются заново, поэтому улика меняется по причинам, не имеющим отношения к пере-спросу решённого. Оставлен в инструменте, но в выводы §4.4 не входит. 9. ⛔ **Мой собственный дефект метода, найденный и исправленный по ходу.** Первая версия §4.4-инструмента читала `mined-signature.yaml` и складывала в «улику» ВЫБРАННУЮ передачу — а `note` называет только ЧИСЛО чанков у топ-предложения, но не его текст. Выходило «улика двигалась» у 100 % смен (0 из 12 и 0 из 14 «одинаковых») — число правдоподобное и целиком ложное. Переписано на таблицы стопа; прежний метод описан в комментарии файла, чтобы следующий не повторил. 10. ⛔ **И дефект пина, найденный мутацией, а не глазом.** Утверждение «ридер обязан отказать на незнакомой строке» я сперва проверяла строкой, ДОПИСАННОЙ в конец файла — а её ловит ДРУГОЙ гард («поле вне блока»). Мутация «default → continue» выжила; фикстура пере-построена так, чтобы строка стояла ВНУТРИ блока до первого контекста, и теперь пин краснеет именно на ней. ##### Адверсариальный проход по СВОЕЙ готовой работе (§5 промта) — восемь находок, все починены Проход вёлся двумя руками: мой собственный разбор и ОДИН советчик-фабл (разрешённый промтом), которому было велено атаковать и грунтовать каждую находку адресом. Каждую его посылку я пере-проверила деревом сама; ниже — то, что подтвердилось, и что с этим сделано. 1. ⛔ **Ридер таблицы стопа ПАДАЛ на контексте, который движок пишет сам.** Окно KWIC через границу абзацев несёт `\n\n` (чанкер склеивает абзацы именно так, `AttachKWIC` режет только края), то есть в листе появляется ПУСТАЯ СТРОКА ВНУТРИ контекста — а я читала пустую строку как конец блока терма. Один такой терм делал НЕЧИТАЕМЫМ весь лист и замер невозможным. Воспроизведено моим собственным тестом до починки (`a field line outside any term block`), починено лукэхедом (пустая строка — граница, только если следующая непустая ОТКРЫВАЕТ ряд), фикстура раунд-трипа теперь несёт ровно такой контекст, посадка `BANK-stop-table-reader-breaks-on-a-paragraph-break`. 2. ⛔ **Разбор списка ФАБРИКОВАЛ элементы.** Писатель склеивает `evidence` через `", "`, а майнер пишет одним элементом `«related to mined 青山, 白山»` — то есть с запятой ВНУТРИ. Мой `splitList` возвращал три элемента там, где в прогоне было два, молча, при сходящемся числе рядов. Починено правилом «строка списка сохраняется ЦЕЛИКОМ»: сепараторы этого формата не экранируются, поэтому ридер не изобретает элементов, а раунд-трип утверждает асимметрию явно (`whole`), посадка `BANK-stop-table-reader-splits-a-list-item-in-two`. Тот же класс у `CONTRADICTS`/`THE BANK ALREADY HOLDS` закрыт тем же правилом. 3. ⛔ **Реестр `roleInjectionKeys` был НЕПОЛОН для редактора.** `RenderEditorConstraintBlock` открывается тем же гейтом `HasData()`, а `HasData` читает ГЛОССАРНЫЙ заголовок — значит цель с `editor_header` и без `glossary_header` проходила бы гард и рендерила ноль байт. Сегодня это скрыто объединением ключей (во всех четырёх боевых пайплайнах есть обе роли), но реестр обязан быть верен ПО РОЛИ, а не по совпадению. Ключи редактора теперь `{glossary_header, editor_header}`, посадка перенаведена. 4. ⛔ **Комментарий у файла данных называл пин, которого НЕ СУЩЕСТВУЕТ** (`TestTheShippingConfigsDeclineNothingByProse`; `grep` даёт единственный хит — сам комментарий). Это ровно «якорь на несуществующую цель», который у нас класс ошибки. Заменён на два настоящих имени. 5. ⛔ **Нулевое значение `StopContestOpts` было АКТИВНЫМ армом.** Сентинел «`-1` выключает» означал, что структура, которую никто не заполнял, выбирала все строки с `conf=0` — самые срочные строки листа. Файл, объявляющий «умолчаний здесь нет», не вправе иметь нулевое значение с поведением. Арм получил свой флаг `UseConf`, посадка `BANK-stop-contest-zero-value-is-an-active-arm`. 6. ⚠ **JSON-сайдкар не несёт метки «не спрашивали»** (`bankexport.go` такого поля не пишет), поэтому на ВТОРОЙ покупке решённая банком строка выглядела бы как «ответа не было», портя оба знаменателя. Харнесс теперь печатает это предупреждение для JSON-источников и велит брать ТАБЛИЦУ стопа; все итоговые числа сняты с таблиц. 7. ⚠ **В «строках, которые спасло бы правило не-переспрашивать», сидели строки, которых никто не спрашивал.** Решённые банком и неотвеченные в ОБЕИХ покупках теперь считаются отдельными классами и из этого числа исключены. 8. ⚠ **Неточность доккомментария:** одиночный `—` до счётчика `NoLetters` не доходит — его отбивает минимальная длина `wellFormedLemma` на проверку раньше. Формулировки в коде и в WARN поправлены (в этом отчёте порядок был назван верно с самого начала). **Проверено и дефекта НЕ найдено** (называю, чтобы был виден охват): путь подписи банка `bank-apply` новым отказом НЕ задет — он открывает стор напрямую (`internal/pipeline/bankdecisions.go:179`=`lock, err := store.LockProject(book.ProjectDB)`), мимо `openRunner`; в `cmd/tmctl/main.go` на запись раннер открывают только `translate` (`:280`) и `redrive` (`:484`), все прочие — `NewReadOnlyRunner`. ⚠ Следствие, которое я всё же НАЗЫВАЮ: `redrive --dry-run` идёт через тот же `NewRunner`, поэтому книга с уже оплаченным банком и целью без текстов не получит даже $0-проекцию плана — это тот же класс, что у соседних отказов (ключи, роутинг), но на УЖЕ оплаченной книге он режет и бесплатный путь. Также проверено и чисто: порядок ветвей `ParseReply` (сентинел → фраза → форма → буквы → эхо → язык), симметрия свёртки фраз, отсутствие кириллицы и CJK в строковых литералах новых файлов вне тестов и комментариев, и то, что ни одна книга дерева не имеет цели, отличной от `ru`. ⛔ **ПОПРАВКА 16.09, и она про мой метод, а не про вывод:** число «16 книг» я взяла из отчёта советчика и НЕ пере-снимала — ровно то заимствование чужого числа, которое этот же отчёт запрещает в другом месте. Пере-снято моей рукой: `command grep -rl '^target_lang:'` по корню даёт **24 файла**, `command grep -rh '^target_lang:'` — **30 строк, все `ru`, не-`ru` ноль** (`command grep`, а не обёртка, иначе каталог `books/` не читается). Вывод держится; число было не моё. ##### Ось денег (§6 промта): что каждый механизм делает с ЧУЖИМИ деньгами, если сработает ошибочно | механизм | ошибка в сторону «сработал зря» | ошибка в сторону «не сработал» | почему выбран такой перекос | |---|---|---|---| | отказ §4.1 | прогон, который сегодня работает, не стартует. Денег НЕ теряется — отказ стоит ДО первого платного вызова, — теряется время оператора | книга покупает банк-роли и стоп подписи, а в модель не уходит ни байта банка: заплачено за то, чего никто не увидит | перекос в сторону отказа выбран сознательно: цена ложного отказа — сообщение с рецептом, цена молчания — оплаченная волна. Ложный отказ при этом сужен пятью армами: книга БЕЗ банка любой цели проходит свободно (отдельный негативный подтест) | | корзина «мусор» §4.2 | законная передача без букв (чистый символ) теряется — одна строка предложения, владелец подпишет рукой | «90» становится каноном книги на всю книгу и едет редактору законом | направление объявлено в коде тем же доводом, что у соседнего экрана языка ответа (`OffLanguage`) | | реестр отказных фраз §4.2 | оплаченная ВЕРНАЯ передача выбрасывается из банка, строка пере-спрашивается на следующей покупке — а ретрая у банк-ролей нет вовсе (ряд 438) | отказ прозой остаётся каноном | именно поэтому реестр лендится ПУСТЫМ и совпадение строгое: цена ложного срабатывания здесь выше цены пропуска | | предикаты §4.3 | сегодня — ничего: платного потребителя нет ни одного, предикат никем не читается | то же | маршрутизировать по неизмеренному признаку запрещает сам пак; сначала популяция, потом маршрутизатор | | харнесс §4.3–4.4 | денег не тратит и не может: читает только файлы, `immutable=1` | — | но ЧИСЛО, снятое неверно, обоснует неверное денежное решение следующего пака, и поэтому у двух его методических правил стоят собственные пины (`cmd/tmbankprobe/main_test.go`) | ##### Что передаётся на лендинг **29 путей в `backend/` (14 изменённых + 15 новых) плюс `docs/PROGRESS.md`; счёт снят `git status --short --untracked-files=all backend/`.** Новые файлы (15): `internal/pipeline/injectionpreflight.go` · `internal/pipeline/stopcontest.go` · `internal/pipeline/stopcontest_test.go` · `internal/pipeline/bankstopparse.go` · `internal/pipeline/bankstopparse_test.go` · `internal/pipeline/bankreplyparse_test.go` · `internal/terminology/contested.go` · `internal/terminology/contested_test.go` · `internal/terminology/decline_test.go` · `internal/lang/declinephrases.go` · `internal/lang/declinephrases_test.go` · `internal/lang/bankdata/decline-phrases.txt` · `cmd/tmbankprobe/main.go` · `cmd/tmbankprobe/passes.go` · `cmd/tmbankprobe/main_test.go`. Изменённые (14): `internal/pipeline/runner.go` · `chunkrun.go` · `mining.go` · `terminologist.go` · `contourpreflight_test.go` · `testdata/operator-messages.txt` (+3 строки моих сообщений, +2 восстановленные — см. ниже) · `internal/lang/embedded.go` · `bankdata.go` · `embedded_test.go` · `internal/terminology/terminology.go` и три его тест-файла (механическая правка 13 мест вызова `ParseReply` под новый параметр) · `cmd/tmmutate/mutations.json`. ⚠ **Одна правка в `operator-messages.txt` требует взгляда при лендинге:** каталог держит ОДНУ строку на КАЖДЫЙ ВЫЗОВ, поэтому две его строки законно повторяются дважды (`quality.go QualityReport` и `terminologist.go runBankRoleBatches `). Мой первый скрипт вставки применил `set()` и обе дубли съел; замечено сразу по красному гейту, восстановлено, итоговый диф — **+5 строк и ни одного удаления** (`git diff --stat` это и показывает). ##### Как повторить замеры Улики (оригиналы НЕ трогать, копировать): `~/tm-coldrun-a/evidence/bankstop-paid/project.db.bank-stop.txt` (A, покупка 1) · `~/tm-coldrun-a/stand/books/bk_ROEHZBD46ALFI43E/project.db.bank-stop.txt` (A, покупка 2) · `~/tm-coldrun-b/evidence/paid-bankstop/project.db.bank-stop.txt` (B, покупка 1) · `~/tm-coldrun-b/stand/books/bk_NH6275ZIRFFTLZHG/project.db.bank-stop.txt` (B, покупка 2) — последние два адреса промт не называл, я их нашла: у B есть СВОЙ каталог книги в стенде, а в нём вторая таблица стопа и БД после прогона. ``` cd backend go run ./cmd/tmbankprobe -sheet A-pass1= -sheet A-pass2= -sheet B-pass1= -sheet B-pass2= -db A-after=<копия A project.db> -db B-at-stop=<копия B project.db> -passes A=, -passes B=, ``` ##### Гейт зоны и мутации — числа **`make battery` (цель зоны, а не `go test`): `MAKE_EXIT=0` — и это прогон ПОСЛЕ починок адверсариального прохода, на том дереве, которое я передаю.** Линтер — `0 issues.` (прогонов было три: первый красный на `errcheck` в моём же новом тесте — `runToSignatureStop` возвращает значение, реализующее `error`, лечится `_ =`, как у соседей; второй зелёный; третий — итоговый, после правок адверсариального прохода. Цель `lint` стоит ДО `test`, поэтому «тесты зелёные» до первой починки не значило ничего). **Полнота сверена СПИСКОМ, а не хвостом:** `go list ./...` = **24** пакета, вердиктов в логе **24**, `comm -23` пуст — и контрольный перевёрнутый `comm -13` тоже пуст. `FAIL` — **0**. ⚠ Пакетов стало 24, а не 23 как в акте `D39.255`: прибавился `cmd/tmbankprobe`. **SKIP — 4, названы поимённо:** `TestHelperEventsRun` и `TestHelperKillLoop` (хелперы подпроцессов, скипаются по построению); `TestMinerFullBookParity` (нет стенд-данных: `eval/exp16/data/jieba_dict_general_zh.txt` отсутствует — проверено `ls`); `TestCorpusBankKeyConflicts` (нужен `TM_CORPUS`). ⭐ **Последний я всё-таки прогнала** — на своих КОПИЯХ улик, чтобы не трогать оригиналы: `TM_CORPUS=<копии> go test ./internal/pipeline/ -run '^TestCorpusBankKeyConflicts$'` → PASS, и он печатает свою популяцию с контролем: `.db walked=3 · with a glossary table=3 · rows read=135 · approved=4 draft=131 · books with ANY conflict=0 · CONTROL: a planted contradicting unsigned row is reported on 2 of 2 books`. **Мутации: каталог 441 → 478 (+37), помеченных `battery` 230 → 267.** Прогнаны ВСЕ 37, по одному прогону на запись, на отдельных копиях дерева (одна копия — один мутатор; когда на первой шёл полный прогон подмножества, одиночные шли на ВТОРОЙ). Итог: **37 RED**, но не с первого раза, и обе осечки записаны, потому что они про метод: - **1 НЕИЗМЕРЕННАЯ** (`BANK-silent-target-delta-door-closed`): посадка не собиралась — `present` становился неиспользуемой переменной. «Не собралось» инструмент честно отдал отдельным исходом (`nothing ran`), а не зачёл как поимку; посадка пере-сделана на возврат `false` и пере-прогнана — RED. - **1 ВЫЖИВШАЯ** (`BANK-stop-table-reader-skips-what-it-cannot-read`), и она нашла настоящую дыру В ПИНЕ: моё утверждение «ридер обязан отказать на незнакомой строке» проверялось строкой, дописанной в КОНЕЦ файла, а её ловит ДРУГОЙ гард («поле вне блока»). Фикстура пере-построена — строка стоит ВНУТРИ блока до первого контекста, — и пин стал краснеть именно на том гарде, о котором говорит. Пере-прогон — RED. - `anchors swept: 0 of 478` — ни одна запись каталога не протухла от моих правок. Сверх того я прогнала СОБСТВЕННЫЙ контроль по ВСЕМ 478 записям: строка-цель каждой найдена в дереве РОВНО один раз (прибор — `python3`, печатает число несовпавших; после правок адверсариального прохода две записи пришлось перенаводить, и контроль их нашёл). Тот же контроль — способ убедиться, что мутация не осталась в НАСТОЯЩЕМ дереве: пропавшая цель означала бы применённую правку; несовпавших 0 из 478. - ⚠ **Две последние записи стерегут не движок, а МОЙ ПРИБОР** (`cmd/tmbankprobe/main_test.go`): «строка, решённая банком, не попадает ни в один знаменатель» и «сравниваемый вход НЕ несёт ответа». Оба правила я сперва нарушила, оба давали правдоподобные числа, и оба теперь краснеют посадкой. ##### Пере-снято вторым прибором Каждое число сетки снято ДВАЖДЫ и разными приборами: Go-харнессом (`tmbankprobe`, движковые типы и движковый ридер) и независимым разбором на `python3` тех же файлов. Сошлись: `conventions ≥ 2` — 9 (A) и 8 (B); распределение конвенций B `{1:58, 2:4, 3:3, 4:1}`; `conf ≤ 70` на B — 25 (сумма гистограммы `{50:2, 55:8, 60:4, 65:1, 68:1, 70:9}`); `invented` — 11 и 17; конфликты — 0 и 0 при непустых листах 660 и 648 строк. Сверх того JSON-сайдкар и ТАБЛИЦА стопа одной и той же покупки прочитаны двумя разными загрузчиками и сведены строка к строке: расхождений 0 из 66. ##### На чём судилась зелень **Гейт зоны прогнан на МОЁМ дереве** (`cd backend && make battery`), не на чистом `HEAD`: предмет приёмки — дерево сдачи, а на `HEAD` ни одного из новых пинов нет. Полнота прогона сверялась СПИСКОМ (`go list ./...` против вердиктов лога), а не чтением хвоста. ⚠ **Линтер якорей доков на грязном дереве даёт ложные красные** (оркестратор видел 31 против восьми) — я на нём ничего не судила и его не чинила: он читает пути, которых в моей зоне нет. ##### Остаток, названный на момент сдачи 1. ⭐ **ЗАКРЫТО ПОСЛЕ СДАЧИ: полное батарейное подмножество каталога прогнано целиком — `267 mutation(s) run, 0 unexpected outcome(s)`, выживших 0, `anchors swept: 0 of 478`, `TMMUTATE_EXIT=0`** (20:22:48 → 21:15:39, отдельная копия `~/tm-mut-11/tree`). ⛔ **И контроль, без которого это утверждение было бы о другом дереве:** `diff -rq backend ~/tm-mut-11/tree` — ноль расхождений, то есть измеренная копия байт-идентична тому бэкенду, который залендили. На момент самой сдачи прогон ещё шёл, и в акт он входит этим числом, а не молчанием. ⚠ Первый запуск я ОСТАНОВИЛА на 165 записях из 267 (выживших 0) и перезапустила с нуля: посреди него легли починки адверсариального прохода, а прогон шёл по ЗАМОРОЖЕННОЙ копии — его вердикт был бы о дереве, которого уже нет. Частичный лог сохранён отдельно (`mutfull-prefix-tree.log`), и выдавать его за прогон сдачи нельзя. 2. ⚠ **Каталог копий не переживает смену, и это НЕ гипотеза: мой `~/tm-mut-11` снёс оркестратор** (`rm -rf` в окне 19:36–19:43 по слову владельца о сносе мусора; он назвал это сам). Мой первый запуск полного прогона упал на `cp: cannot create directory … No such file or directory` в **19:45:42**, хотя я удаляла только подкаталог `tree`. ⛔ **И вот разбор, который тут важнее признания:** прогон, дошедший до 165 записей, в это окно НЕ попадал — он стартовал в **19:47:15** на каталоге, который я пере-создала, шёл до **20:21:54** и остановлен МНОЮ; в его логе ноль ошибок чтения (единственное совпадение грепа по «cannot» — имя мутации `STOP-the-spend-line-closure-cannot-reach-the-emitter`). То есть его числа недействительны по МОЕЙ причине (дерево до починок), а не по чужому вмешательству, и путать две причины нельзя: у вмешательства вердикт был бы «файла нет», прочитанный как «мутация не поймана». Нынешний прогон начат в **20:22:48**, уже после всего. ⇒ норма, которую стоит держать обеим сторонам: перед сносом чужого каталога спрашивают `ps`, а рабочий каталог живой сессии в репозитории не упоминается ПО ПОСТРОЕНИЮ, поэтому греп по репо его не находит. ##### Вопросы оркестратору (работу не блокируют) — ответы получены 16.09, решения его ⭐ Все три закрыты словом оркестратора при сдаче: (1) реестр ru-фраз — отдельной строкой бэклога с критерием «популяция измерена на сырье», строку заводит он; (2) дизайн персистенции §4.4 — строкой с весом «скоро», формой «состав батча + строки якоря ключом на `request_hash`»; (3) ряд 445 не снимается, а СУЖАЕТСЯ: половина про мусор закрыта, остаток — отказ прозой, инертный до первой фразы. Ниже — как вопросы были поставлены. 1. **Заполнение реестра ru-фразами** — отдельной строкой бэклога с критерием «популяция измерена на сырье», как договорились. Моё предложение по критерию: фраза заводится, когда встречена в ОТВЕТЕ роли на купленном прогоне, а не когда звучит правдоподобно. 2. **Дизайн персистенции §4.4** (состав батча + якорь ключом на `request_hash`) — заводить ли строкой бэклога и в чей пак. 3. **Ряд 445 закрыт наполовину** — мусор стережётся всегда, отказ прозой инертен до первой фразы. Как отмечать в реестре требований. #### ЗАПИСКА-ПЛАН пака «БАНК — ЧТО МОЖНО УЗНАТЬ И ПОЧИНИТЬ ЗА $0» (16.09, сессия `textmachine-main-11`, промт `docs/BACKEND_BANK_ZERO_LAYER_SESSION_PROMPT.md`, ряды 441 · 445 · 459 + замер под 449). НЕ КОММИЧУ — дерево передаю оркестратору №23 Записка стоит ДО первой правки (§7 промта). Пак **$0**: платных вызовов моделей нет ни одного, всё — либо детерминированный код, либо замер по уже купленному сырью прогонов A и B, открываемому **только на чтение**. **Что беру и в каком порядке.** 1. **§4.1 — громкий отказ, когда у ЦЕЛИ нет строк инъекции.** Гейт в `openRunner` рядом с соседним отказом того же рода (`backend/internal/pipeline/runner.go:356`), форма `RefusalBadConfig`, условие шире гейта терминологии (терминология ИЛИ банкнота ИЛИ непустой `glossary_seed` — инъекция строится при `r.baseMemory != nil` мимо гейтов, `backend/internal/pipeline/waverun.go:592`). Текст отказа называет лечение: строки живут в `backend/internal/lang/data/injection.txt`, их добавление двигает `lang.EmbeddedVersion()` ⇒ снапшот. Пин краснеет на ДАННЫХ: фикстура проходит загрузчик и соседний отказ и сверяет СВОЙ текст и класс. 2. **§4.2 — отказ роли перестаёт быть передачей.** Путь (а): сентинел `⟦TM-NO-DST⟧` НЕ трогаю (снятие = отмена ратифицированного `D39.42` п.1), ужесточаю разбор ответа и развожу ДВЕ корзины — отказ (сентинел + отказ прозой) → `Declined`, мусор (`dst` без букв вообще) → `Unanswered`. Реестр отказных фраз — ЯЗЫКОВЫЕ ДАННЫЕ, не литералы в Go. 3. **§4.3 — предикат «спорный» как ДВА предиката** (pre-call на кандидатах до первой траты · post-call на строках стопа) + $0-харнесс реплея по купленным базам + таблица чувствительности по нескольким порогам, на обоих источниках, с обоими ЗАДАННЫМИ промтом знаменателями. 4. **§4.4 — носитель для посылки «новой улики не было»**: что реально менялось во входе между двумя покупками одной строки, либо честный дизайн персистенции, если тел запросов нет. 5. Мутации новых мест — в каталог, не разовым прогоном; гейт зоны `make battery` целиком; адверсариальный проход по своей же готовой работе. **Чем меряю.** Базы прогонов — `python3` + `sqlite3.connect('file:<путь>?mode=ro', uri=True)` (CLI `sqlite3` на машине нет); ключи сайдкаров считаю по ВСЕМ записям, а не по первой; рядом с каждым нулём печатаю контрольную величину. Пины — прогоняю и показываю вывод. Полнота батареи — сверкой СПИСКА `go list ./...` против вердиктов лога, а не чтением хвоста. **Что уже пере-снял своим прибором на входе** (числа промта сошлись): B (`/home/ubuntu/tm-coldrun-b/evidence/paid-bankstop/project.db`) — `glossary` 0, `bank_stop_presented` 67, `request_log` 18, `checkpoints` 24, сайдкар 66 записей, поле `conventions` у 66 из 66, `invented` 17; A (`/home/ubuntu/tm-coldrun-a/stand/books/bk_ROEHZBD46ALFI43E/project.db`) — `glossary` 69, `bank_stop_presented` 70, `request_log` 33, сайдкар 69 записей, `conventions` **0 из 69** (поля нет вовсе), `invented` 11. Девятнадцать якорей промта прогнаны построчно — все 19 указывают туда, куда говорит проза. **Опасности, названные ДО работы** (полный список — в эхо-протоколе оркестратору): - ⛔ **Схемы двух баз РАЗНЫЕ, а не только состояния:** у B 17 таблиц, у A 16 (в A нет `wave_selection`). ⇒ движковый стор этих баз не открываю НИКОГДА: он применит миграции и испортит улику. Go, если понадобится, работает на копии в скретчпаде. - ⛔ **Знаменатель pre-call расходится с таблицей стопа на единицу с каждой стороны:** `bank_stop_presented` 67 против 66 записей сайдкара (B) и 70 против 69 (A). Пока единица не объяснена, «доля спорных» будет утверждением о моём прочтении знаменателя, а не о предмете. - ⚠ **Живая популяция §4.2 — ноль** (`research/35` §2.0, строка Б-5: 0 из 69 и 0 из 66 при контроле 69/69 и 66/66; пере-сниму сам) ⇒ пин по необходимости синтетический, и это называется, а не выдаётся за замер на сырье. - ⚠ **Денежный риск пака — отказные ФРАЗЫ, а не мусор:** ложное срабатывание превращает оплаченную верную передачу в отказ, книга теряет строку канона, а пере-спрос стоит денег на следующей покупке (ретрая у банк-ролей сегодня нет вовсе, ряд 438). ⇒ совпадение строгое, по всему полю, а не по вхождению подстроки. - ⚠ **`HasData()` — предикат ЧАСТИЧНЫЙ:** он спрашивает только `glossary_header`; цель с заголовком глоссария, но без `editor_header`, гейт пройдёт, а редакторский блок отрендерится с пустым заголовком. - ⚠ **У предиката §4.3 в этом паке нет потребителя** (маршрутизация — следующий пак) ⇒ лендится чистой функцией с $0-харнессом, ни один платный путь на него не смотрит; пороги в Go не зашиваю. ## Отчёты бэкенд-паков 07–16.09 — ВЫНЕСЕНЫ В АРХИВ 17.09 > Отчёты десяти паков, ВСЕ закрытые актами (`D39.225` · `D39.226` · `D39.228` · `D39.232` · `D39.240` · > `D39.242` · `D39.245` · `D39.249` · `D39.251` · `D39.255`), уехали в > [`archive/PROGRESS-2026-09-07-16-backend-packs.md`](archive/PROGRESS-2026-09-07-16-backend-packs.md) — **4552 строк**. > Вынесено по заказу владельца 17.09 на снос устаревшего. Живое из этих отчётов живёт нотами и строками > трекера, а не здесь. ⚠ Отчёт пака «БАНК ЗА $0» (`D39.257`) ОСТАВЛЕН выше: он вход следующего банк-пака. ## Отчёты пака «закон банка честно» и петли `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**. > Живое из этих отчётов живёт нотами и строками трекера, а не здесь. ## Полигон — ХРОНИКА ВЫНЕСЕНА В АРХИВ 17.09 Хроника эксп-22/23 и фазы Д (203 строк) — [`archive/PROGRESS-2026-09-17-polygon-chronicle.md`](archive/PROGRESS-2026-09-17-polygon-chronicle.md). Живое из неё держат ряды трекера **482** · **483** · **485** · **237**(б); пинг о якорях закрыт замером. ⚠ Читать срез при онбординге НЕ нужно — только по конкретной ссылке.