diff --git a/docs/BACKLOG.md b/docs/BACKLOG.md index f063e29e..112b2063 100644 --- a/docs/BACKLOG.md +++ b/docs/BACKLOG.md @@ -24,7 +24,7 @@ | 11 | Флип coverage-гейта (`enabled:false`, D12-Q4) — за подписью владельца ; при флипе решить судьбу v1.1 quote-absorption (D12-Q1, Python-first лок-степ) | владелец | когда-нибудь | отдельное решение | D39.34(2) | | 12 | **`postcheck_gate` в hard-gate** — требует пере-замера recall (recall чекеров измерен и низок); ⚠ «fn=0» демоции #10 класс-вакуумен на labels (ноль одно-Han-позитивов, D39.78) — пере-замер обязан добрать одно-Han-позитивы, на «fn=0» не опираться; одно-Han-класс при gate-on вне гейта (Unverified+Demoted); тем же решением строится HARD-value-детектор 成/万 (Q3 §6 — честный hard-gate требует value-чека; либо раньше при ненулевом потоке value-дефектов добора, D39.79; **$0-прототип получен эксп-21: `battery.check_numbers`, симметричный разбор, синтетика 16/16 — D39.117**) · recall существующих гейтов печатал арм C эксп-21 на контаминированном срезе (D39.108/D39.117) | владелец | скоро (⚠ испр. 05.09: `D39.205` п.4 сделал эту строку ПРЕДУСЛОВИЕМ решения владельца по гейту глоссария — прежний вес «когда-нибудь» противоречил ратифицированному; порядок работ — строка 295) (после фазы 2) | отдельное решение | D39.34(2), D24.4+D28.1, D39.39, D39.78, D39.79 | | 13 | **Включение платной петли ремонта + per-class исходы ремонта** (схемное решение принимается вместе) — вернуться при расширении классов детекторов и ненулевом остатке; ⚠ при включении: репэйр-гард №5 после #10 слеп на одно-Han-дифференциал (демоция в обоих прогонах ⇒ 0>0 — репэйр, стёрший верно отрендеренный одно-Han-термин, не ветируется; D39.78-ревью) | владелец | когда-нибудь | отдельное решение | D39.38, D39.39(а), D39.78, CURRENT-STATE | -| 13б | **`speech-cue.txt` zh НЕ шипить до замера голос-флаггера; замера НЕТ (D39.86) — оси не считались НИ РАЗУ.** ⚠ **Причина ПЕРЕ-НАЗВАНА: прежний довод «редакторская волна не гонялась» ПРОТУХ 31.08** (холодный прогон `coldrun-v16` её гонял и оплатил — строка 16); живой блокер — ПУСТОЙ РЕЕСТР профилей, см. ниже. ⚠ **ГЕЙТ ПЕРЕ-СНЯТ 05.09:** прежний требовал «подписанных профилей (строка 24)», а подпись владелец снял (D39.198 п.5) — значит гейтом остаётся ОДНО: первый прогон добора идеала С редакторской волной. ⛔ **Но снятие подписи открыло дыру, и её надо закрыть раньше стройки:** реестр `voices:`/`addresses:` физически заполняет только подпись (`backend/internal/config/seed.go`, греп `no miner emits them`), и если подписи нет — заполняет НИКТО. Вопрос вынесен строкой 24. ⚠ Сам гейт в схеме ЕСТЬ (`internal/config/pipeline.go` `VoiceGate`, пак-19/D39.55). ⚠ `rules=` в отчёте = «гейт СКОНФИГУРИРОВАН», не «отработал» — до фикса читать по знаменателям `replies=` — носитель **292** (испр. 05.09: 105 закрыта D39.200 только половиной (а), знаменатели уехали в 292). Археология дословно — `architecture/13-tech-debt-anchors.md` §Б-13б. ⚠ **ПОПРАВКА 23.08 (№19):** заполнить `voices:`/`addresses:` может только подпись владельца (`internal/seed/seed.go:23`=`Voices and Addresses are the two D21 record types` — «no miner emits them»), а при пустом реестре `RunVoiceChecks` выходит на `!reg.HasData()` ДО ВСЕХ осей, поэтому нулями отдаются и оси, и знаменатели — «ноль флагов» неотличим от «оси не считались». ⚠ Отдельно: `gates.voice` отсутствует в `backend/configs/`, НО в конфигах реальных прогонов (вне git) он ВКЛЮЧЁН — `~/books/gu-zhenren/coldrun-a/pipeline.yaml:68` и `coldrun-b:71`, `enabled: true`; дыра не «оператор забыл включить», а «шаблоны репозитория гейт не несут» | владелец | отложено-до-замера | первый прогон добора идеала С РЕДАКТОРСКОЙ ВОЛНОЙ (оси голоса, строка 24) → отдельное решение | D39.56, PACK19_BUILD §7.2, чат 31.07, D39.86 | +| 13б | **`speech-cue.txt` zh НЕ шипить до замера голос-флаггера; замера НЕТ (D39.86) — оси не считались НИ РАЗУ.** ⚠ **Причина ПЕРЕ-НАЗВАНА: прежний довод «редакторская волна не гонялась» ПРОТУХ 31.08** (холодный прогон `coldrun-v16` её гонял и оплатил — строка 16); живой блокер — ПУСТОЙ РЕЕСТР профилей, см. ниже. ⚠ **ГЕЙТ ПЕРЕ-СНЯТ 05.09:** прежний требовал «подписанных профилей (строка 24)», а подпись владелец снял (D39.198 п.5) — значит гейтом остаётся ОДНО: первый прогон добора идеала С редакторской волной. ⛔ **Но снятие подписи открыло дыру, и её надо закрыть раньше стройки:** реестр `voices:`/`addresses:` физически заполняет только подпись (`backend/internal/config/seed.go`, греп `no miner emits them`), и если подписи нет — заполняет НИКТО. Вопрос вынесен строкой 24. ⚠ Сам гейт в схеме ЕСТЬ (`internal/config/pipeline.go` `VoiceGate`, пак-19/D39.55). ⚠ `rules=` в отчёте = «гейт СКОНФИГУРИРОВАН», не «отработал» — до фикса читать по знаменателям `replies=` — носитель **292** (испр. 05.09: 105 закрыта D39.200 только половиной (а), знаменатели уехали в 292). Археология дословно — `architecture/13-tech-debt-anchors.md` §Б-13б. ⚠ **ПОПРАВКА 23.08 (№19):** заполнить `voices:`/`addresses:` может только подпись владельца (`backend/internal/seed/seed.go:23`=`Voices and Addresses are the two D21 record types` — «no miner emits them»), а при пустом реестре `RunVoiceChecks` выходит на `!reg.HasData()` ДО ВСЕХ осей, поэтому нулями отдаются и оси, и знаменатели — «ноль флагов» неотличим от «оси не считались». ⚠ Отдельно: `gates.voice` отсутствует в `backend/configs/`, НО в конфигах реальных прогонов (вне git) он ВКЛЮЧЁН — `~/books/gu-zhenren/coldrun-a/pipeline.yaml:68` и `coldrun-b:71`, `enabled: true`; дыра не «оператор забыл включить», а «шаблоны репозитория гейт не несут» | владелец | отложено-до-замера | первый прогон добора идеала С РЕДАКТОРСКОЙ ВОЛНОЙ (оси голоса, строка 24) → отдельное решение | D39.56, PACK19_BUILD §7.2, чат 31.07, D39.86 | | 14 | **Четыре data-инженерных флага фазы-2 общности, каждый с рекомендованным дизайном** (§5 отчёта): ё-фолд → target-данные (`char_fold`; смена сигнатуры core-примитива через вердикт-несущий банк, сдвиг `memory_version`) · segmentation-фолбэк громким (ломает контракт corridor-фолбэка `pipeline.go:839-848` + голден-фикстура на нём; лечение — объявить блок в голден-yaml) · `Fertility` per-script map (калибровка ждёт боевого токенизатора) · `source-encoding.txt` + Go-реестр декодеров | владелец | когда-нибудь (следующий пак общности) | отдельное решение | D39.64, GENERALITY_PHASE2 §5.1–5.4 | | 86 | **Мелкие открытые решения одним списком** (свип D39.66): echo-семантика дропнутого c-lite-члена (D39.18 — оставить pre-c-lite?) · magnitude-кап тяжёлой CJK-утечки (D38.3 п.4в; сейчас strip+flag) · ⚠ дописка 07.09: `internal/lang/data/zh/numeral.txt` отстаёт от эталона `cjk-section.txt` на `〇两兩` — намеренно или недосмотр? Потребитель — канал «числительное + ранг-слово» майнера (research/33 §7.1) | владелец | когда-нибудь | отдельные решения | D39.66, D39.69(feed_cap закрыт §1) | | **— ХВОСТЫ ХОЛОДНОГО ПРОГОНА (исполнен достаточно, D39.58; Р7 владельца) —** | | | | | | @@ -35,7 +35,7 @@ | 90 | **Ф2-кандидаты 02-mvp-плана без носителя** (свип-хвост, D39.73): CometKiwi/T-index метрики судьи · Batch API судьи (экономия) · llama-server-интеграция локали · стриминг — взять/закрыть при пилот-препе; + H16 самоулучшение (V3-п.2, ПТ-26): дизайн петли по данным судьи — тем же препом | полигон/бэкенд | когда-нибудь (Ф2.5) | пилот-преп-промт (с 85) | 02-mvp-plan, D39.66, D39.73, D39.80 | | **— НАХОДКИ СВИПА ПОЛНОТЫ (D39.66: 951 обязательство проверено, потери возвращены в трекер) —** | | | | | | | 80 | **Резюме-слой памяти** — проза-суммарайзер ЗАКРЫТ (D39.69); строка = ГЕЙТ ПИЛОТА Ф2.5: первый деливерабл пилота — «допускает ли автономная нарратив-состояние-строка ДЕТЕРМИНИРОВАННЫЙ верификатор (source-anchored) — или это D1-компаундинг со схемой»; не-покрытые классы (source-anchored reveal · арк-колбэки без ключа) реальны, но не измерены как дефект | Ф2.5 (Q3 подтверждён D39.70) | когда-нибудь (пилот) | Ф2.5 пре-рег | D25 п.8–9, D39.66, D39.69 | -| 81 | **ja-преп B6-ja (сужено пост-сверкой D39.66)**: Поливанов-валидатор (`translit_policy` = «Phase 2»-заглушка, `backend/internal/store/migrate.go:187`=`translit_policy TEXT` и `backend/internal/store/migrate.go:195`=`ruby_reading`) + kana-омограф POS/known-word гейтинг / B6-токенизатор (`backend/internal/membank/memory.go:1184`=`KANA and HAN are deliberately NOT boundary-checked`); чек-лист kana-алиасов сида УЖЕ построен (backend/README §ja + `AttachRubyAliasesToManual`) — остаток в нём только дизамбигуация двойных чтений (тот же B6) | бэкенд | когда-нибудь (перед ja→ru) | ja→ru-пак (рядом 35) | D16.4, D17.1, D18, D39.66 | +| 81 | **ja-преп B6-ja (сужено пост-сверкой D39.66)**: Поливанов-валидатор (`translit_policy` = «Phase 2»-заглушка, `backend/internal/store/migrate.go:187`=`translit_policy TEXT` и `backend/internal/store/migrate.go:195`=`ruby_reading`) + kana-омограф POS/known-word гейтинг / B6-токенизатор (`backend/internal/membank/memory.go:1185`=`KANA and HAN are deliberately NOT boundary-checked`); чек-лист kana-алиасов сида УЖЕ построен (backend/README §ja + `AttachRubyAliasesToManual`) — остаток в нём только дизамбигуация двойных чтений (тот же B6) | бэкенд | когда-нибудь (перед ja→ru) | ja→ru-пак (рядом 35) | D16.4, D17.1, D18, D39.66 | | 82 | **Морфо-гейт РОДА** (C3: русский глагол прош. вр. при gender=hidden = механический спойлер-канал; «жалоба №1 читателей MTL»; python-сайдкар/pymorphy, связка с морфопроходом Decl из 73). **$0-прототип получен эксп-21** (`battery.check_gender`: карточки из подписанного сида, фильтр по именительному падежу, 86–112 сверок/арм — D39.117); движковый гейт не построен | бэкенд | когда-нибудь (Ф2-гейты) | отдельный пак (с 52) | 06-реестр C3, research/12, D39.66, **D39.117** | | 85 | **Пилот-преп добор** (к переупаковке PACKAGE4): Bertalign GOLD-пары + zh→ru spot-check (D29.2в; GPL-тулинг отдельно) · fidelity-каскад R2 shadow с корпус-подготовкой (D25.2) · exp08 v3 пере-съём COGS до фиксации budget_usd (D21.8) | полигон | когда-нибудь (Ф2.5) | пилот-преп-промт | D25, D29, D21.8, D39.66 | | **— ПАК-21 «чекеры»: РАСТВОРЁН (D39.62); шестёрка исполнена 2/6 фазой 2 (D39.64: #11 · строка 26), остаток — ниже —** | | | | | | @@ -117,7 +117,7 @@ | 197 | **Фикс-лист приёмки пака честности ФЧ-1…ФЧ-8** — восемь пунктов класса «заявленное не прибито» и «текст обещает больше числа», ни один не блокировал лендинг. **Тело списка дословно, с весами и с секцией «что НЕ проверено», — [archive/PROGRESS-2026-08-17.md](archive/PROGRESS-2026-08-17.md), запись приёмки №18** (D39.149). Здесь держим только ратифицированное: **ФЧ-5 РЕШЁН владельцем 17.08 (D39.150): прайсить по модели, которую стадия резолвит СЕЙЧАС, + округление вверх и оговорка в тексте согласия.** Носителя-сессии НЕТ — по слову владельца 17.08 пока только записано | бэкенд | скоро (следующее касание денежного пути; ФЧ-5 обязателен до первого пере-прогона со сменой модели) ⚠ **СОСТАВ ПЕРЕ-СКОУПЛЕН 04.09:** ФЧ-1/ФЧ-4/ФЧ-5 закрыты паком «число согласия» (D39.187); **ФЧ-6 по коду выглядит ЗАКРЫТЫМ** — отказ проекции репортится базисом, отчёт не валится (`backend/internal/pipeline/status.go`, греп `RebillBasisFailed`); **ФЧ-7 отдан проверкой** в вайр-батч (воспроизвести панику поверх пойманного потолка, чинить только если воспроизводится); **ФЧ-2/ФЧ-3/ФЧ-8 НЕ ПРОВЕРЕНЫ никем** и остаются живым остатком строки. | дофикс-промт ЛИБО попутно ближайшим паком | **D39.149**, **D39.150** | | 198 | **Апгрейд движка стирает замечания и счётчики книги БЕЗВОЗВРАТНО — композиция двух половин, каждая известна по отдельности** (приёмка P7, линза «вне карты», обе половины пере-прочитаны оркестратором). Платформа при смене `manifest_key` сносит ВСЕ `unit_resolutions` книги (`platform/internal/pgstore/readmodel.go:243`=`delete from unit_resolutions where book_id` — ⚠ испр. 16.09: было :164-165), рассчитывая, что поток их пере-наполнит; движок анонсирует юнит РОВНО ОДИН РАЗ за жизнь книги — ключ `unit::::` БЕЗ метки нарезки (`backend/internal/pipeline/events.go:436`=`unit:%s:%s:%d:%d`), а леджер анонсов переживает прогоны (`backend/internal/store/outbox.go:130`=`already announced, by this process or by one that ran before it` — ⚠ испр. 16.09: было :96 «already announced… by one that ran before it») ⇒ совпавшие координаты не переанонсируются НИКОГДА. Обостряется порядком: долг на материализацию ставится только на ГРАНИЦАХ работы, поэтому первая зачистка после апгрейда случается в КОНЦЕ первого пост-апгрейдного прогона и сносит замечания ТОГО ЖЕ прогона, за который заплачено. Следствия на проводе: «0 из N» на переведённой книге навсегда · шкала снова предлагает купить переведённое · замечания читателя исчезают. **Лечится с обеих сторон:** движковая половина — метка нарезки в ключе анонса (решение зоны движка), платформенная — не сносить вслепую либо восстанавливать из экспорта. ⚠ Гейт холодного прогона: смысл упражнения — гонять книгу против МЕНЯЮЩЕГОСЯ движка, то есть первый же апгрейд обнулит библиотеку | бэкенд + платформа | **скоро (до первого реального пользователя И до холодного прогона с апгрейдами)** | связка: решение по ключу анонса в движке → правка платформы | приёмка P7 (D39.153) | | 201 | **Движковое «Глава N» доезжает читателю ВНУТРИ текста, обходя дисциплину `heading: null`** (линза шва P7, пере-прочитано оркестратором): `backend/internal/pipeline/export.go:58`=`ApplyHeading` (испр. оркестратором №20 30.08: якорь уезжал с `:230` и с `:266` — код растёт) приклеивает детерминированный порядковый к экспортному тексту первой юнит-главы (`ce.FinalText = chunk.ApplyHeading(...)`), колонка `Source` при этом остаётся heading-stripped. Платформа переносит обе как есть и честно отдаёт `heading: null` — то есть клиент нарисует СВОЙ порядковый на языке своего интерфейса над абзацем, который уже начинается с русского «Глава N», а исходная колонка соответствующего маркера не несёт: пара визуально рассинхронизирована на каждой первой главе. Конкретное следствие открытого К-2 контракта; родня движковой строки **160** (глава без заголовка) | бэкенд | когда-нибудь (с 160) | отдельное решение | приёмка P7 (D39.153) | -| 203 | **Хвосты контракта после синка 0.4.0 — ОТКРЫТ ОДИН ПУНКТ, остальное исполнено** (тела релеев — `platform/docs/archive/P7_ACCEPTANCE_HANDOFF_2026-08-17.md` §7; сюда переписан НЕ текст, а статус — один носитель на факт). **ИСПОЛНЕНЫ и сверены грепом при лендинге:** (а) минором 0.5.0 (D39.161) · (б) · (д) · (и) поле `stop_requested` (D39.152) · (л)(м)(н)(о) контрактной сессией — остаток по фразам Приложения А несёт строка **204** и лист владельца. **(г) наполовину** — `unspecified` ратифицирован в каноне (`docs/architecture/14-api-contract/openapi.yaml:2305`=`is reserved and is the server` (⚠ испр. 17.09: было :2200)), открыта только ГРАНИЦА ступеней замечаний (две ступени при девяти рангах движка); ⚠ её прежний носитель — строка 148 — СНЯТ 21.08 по слову владельца. **(з) СНЯТ как ратификация 22.08 сквозной трассировкой (разбор, на который ссылается строка 191):** конфликта моделей НЕТ — гейт движка проверяет полноту не ПОДПИСЕЙ, а ФАЙЛА решений, и ОДИН файл со всем банком его снимает (`loadMinedDelta` штампует только `Source`, `mining.go:855-867` → опущенный статус дефолтится в `approved`, `membank/memseed.go:130`=`status = "approved"` → `unsignedEngineSurfaces` выбрасывает лишь `Source=="mined" && Status!="approved"`, `mining.go:710-719`). Пере-диспозиция 27.08 (D39.158 п.7): движковый гейт полноты УСТРАНЁН, не обойдён; остаётся снять обход в платформе — одна боевая строка (`platform/internal/runs/spawn.go`, `--verify-bank` не передаётся на resume) плюс семь строк ставшего ложным обоснования, работа платформенного пака. **ОТКРЫТО РЕАЛЬНО — (к):** ключ `project_db` в `book.yaml`, договорить, кто им владеет: шаблон оператора его не содержит, движок делает необязательным. ⚠ Следствие «на штатном деплое банк не читается» ОПРОВЕРГНУТО живым кодом: путь публикует ДВИЖОК конвертом артефактов, пустой путь — ГРОМКИЙ отказ (`platform/internal/runner/artifacts.go:39`=`the engine published no bank read-out path`); остаток (к) чисто договорной| контракт/доки | скоро (следующее касание контракта) | контрактная сессия | приёмка P7 (D39.153) | +| 203 | **Хвосты контракта после синка 0.4.0 — ОТКРЫТ ОДИН ПУНКТ, остальное исполнено** (тела релеев — `platform/docs/archive/P7_ACCEPTANCE_HANDOFF_2026-08-17.md` §7; сюда переписан НЕ текст, а статус — один носитель на факт). **ИСПОЛНЕНЫ и сверены грепом при лендинге:** (а) минором 0.5.0 (D39.161) · (б) · (д) · (и) поле `stop_requested` (D39.152) · (л)(м)(н)(о) контрактной сессией — остаток по фразам Приложения А несёт строка **204** и лист владельца. **(г) наполовину** — `unspecified` ратифицирован в каноне (`docs/architecture/14-api-contract/openapi.yaml:2305`=`is reserved and is the server` (⚠ испр. 17.09: было :2200)), открыта только ГРАНИЦА ступеней замечаний (две ступени при девяти рангах движка); ⚠ её прежний носитель — строка 148 — СНЯТ 21.08 по слову владельца. **(з) СНЯТ как ратификация 22.08 сквозной трассировкой (разбор, на который ссылается строка 191):** конфликта моделей НЕТ — гейт движка проверяет полноту не ПОДПИСЕЙ, а ФАЙЛА решений, и ОДИН файл со всем банком его снимает (`loadMinedDelta` штампует только `Source`, `mining.go:855-867` → опущенный статус дефолтится в `approved`, `backend/internal/membank/memseed.go:130`=`status = "approved"` → `unsignedEngineSurfaces` выбрасывает лишь `Source=="mined" && Status!="approved"`, `mining.go:710-719`). Пере-диспозиция 27.08 (D39.158 п.7): движковый гейт полноты УСТРАНЁН, не обойдён; остаётся снять обход в платформе — одна боевая строка (`platform/internal/runs/spawn.go`, `--verify-bank` не передаётся на resume) плюс семь строк ставшего ложным обоснования, работа платформенного пака. **ОТКРЫТО РЕАЛЬНО — (к):** ключ `project_db` в `book.yaml`, договорить, кто им владеет: шаблон оператора его не содержит, движок делает необязательным. ⚠ Следствие «на штатном деплое банк не читается» ОПРОВЕРГНУТО живым кодом: путь публикует ДВИЖОК конвертом артефактов, пустой путь — ГРОМКИЙ отказ (`platform/internal/runner/artifacts.go:39`=`the engine published no bank read-out path`); остаток (к) чисто договорной| контракт/доки | скоро (следующее касание контракта) | контрактная сессия | приёмка P7 (D39.153) | | 204 | **Движок не публикует причины флагов ДАННЫМИ — карта причин у платформы рукописная и расходится молча** (релей §7(в) хендоффа P7; зона платформы в чужой бэклог не пишет и просила строку сюда — `platform/docs/archive/platform-PROGRESS-P7.md:206`=`ПИНГ ОРКЕСТРАТОРУ`). Сегодня `platform/internal/ingest/notes.go` держит рукописную копию закрытого словаря ЧУЖОЙ зоны: причин движка **16** (испр. 05.09 — шестнадцатой приехала `off_target_lang` → `wrong_language` с минором 0.10.0; прежняя редакция говорила 15 и это ровно то расхождение, которое строка предсказывала) → коды замечаний контракта. Импортировать движок платформе нельзя (D39.85 — разные модули), поэтому расхождение появится молча в тот день, когда движок добавит причину: платформа отдаст `unspecified` и напишет ERROR в лог, то есть деградация честная, но карта протухнет незаметно. ⚠ **Правила заполнения контрактных фраз по этим причинам УЖЕ НАПИСАНЫ** и выводить их заново не надо — компаньон `14-api-contract/README.md`, греп `по ДОККОММЕНТУ` (фраза пишется по доккомменту `disposition.go`, а не по имени константы; класс 2 схлопывается в ОДИН код). Лечение: движок публикует свой словарь причин артефактом-данными (тем же классом, что манифест и сайдкары банка), платформа читает его вместо копии. ⚠ Класс: носителем был ТОЛЬКО регистр платформы (PD-246) — обязательство к ЧУЖОЙ зоне жило внутри зоны автора | бэкенд | когда-нибудь (со следующим касанием эмиссии флагов) | отдельное решение | приёмка P7 (D39.153), релей §7(в) | | 207 | **Пол самосогласованности манифеста стоит только у материализатора, интейк тот же документ ПРИНИМАЕТ — и по такой книге можно ОПЛАТИТЬ прогон** (`PD-367`, вторая волна ревью P8-FIX). Манифест `{ChaptersTotal: 120, UnitsTotal: 400}` с пустым списком глав `Whole()` отвергает, а `books.Parse` заводит книгу `not_started` с `chapter_count=120` и пустым деревом; потолок считается ОТ `chapter_count`. **Очевидное лекарство опровергнуто исполнением самой зоной:** применить `Whole()` на интейке нельзя — вся батарея интейка ездит на манифестах без списка глав, контракт интейка это только счётчики. Значит решение не зонное: либо контракт интейка меняется, либо пол ставится в другом месте цепи | оркестратор → платформа | скоро | нужно решение (лекарство ломает запиненный контракт интейка) | D39.154 п.10, `PD-367` | | 209 | **Риг живых проб не может залогировать тела запросов ни при каких env** (находка бэкенд-пака честности 17.08, оставшаяся без носителя до аудита доков 22.08): `LOG_LLM_BODIES=1`+`LOG_LEVEL=debug` объявлены носителем тел, но ключ читается из `obs.ReqInfo` контекста, а `live_reprobe_test.go` строит ctx БЕЗ `WithReqInfo` — гейт `obs/logging.go` не пропускает. Обход, которым пользовались: ручной дамп сообщений в файл. Цена — каждая живая проба, которой нужно прочитать провод глазами, платит за обход заново | бэкенд | когда-нибудь (следующее касание рига живых проб) | малое касание (`WithReqInfo` в риге) + пин | пак честности 17.08, вынесено аудитом доков 22.08 | @@ -146,7 +146,7 @@ | 50 | F3-остаток идемпотентности | бэкенд | когда-нибудь | отдельное решение | D39.34(4) | | 51 | `human_override` LOCK (D29 п.1г, в коде 0 вхождений) | бэкенд | когда-нибудь | отдельное решение | D39.34(4) | | 52 | **Ф2-гейты вне идеала**: морфо-гейты канцелярита + L1-лемматизация (python-сайдкар) · полный OpenCC · опциональный пре-перевод гейт ; состав явно: канцелярит + РОД (строка 82) + класс Ф2-гейтов карты 04-unhappy (обсцен-гейт/феминитивы/время сцены — состав решить паком) ; + класс идиоматики (свип-хвост, D39.73): сехоуюй-словарь · вэньянь-классификатор (zh) · васэй-эйго ложные друзья (к ja-паку 81) — данные пары или закрытие «банк книги покрывает» тем же паком | бэкенд | когда-нибудь | отдельное решение | D39.34(4) | -| 54 | Масштаб целой книги: волны/каденс/потолки/ETA на сотнях глав (гоняли максимум 10; книга 7,78 млн симв., ~2284 раздела). ⚠ **Дописка инвентаря №18 (D39.147 п.2г):** жёстких потолков размера в коде НЕТ, но исходник читается в память целиком (`backend/internal/chunk/ingest.go:210`=`raw, err := os.ReadFile(p)` — ⚠ испр. 16.09: было :98), чтения стора беспагинационны под `opTimeout = 10s` (`store/store.go:39`=`var opTimeout = 10 * time.Second`) и бюджеты нарезки калиброваны на 25 главах (`backend/internal/config/pipeline.go:122`=`the 25-chapter rerun` — ⚠ испр. 16.09: было :126-138) — ни одно из трёх на 2283 главах не проверено ничем | бэкенд | когда-нибудь (последним по курсу) | МАСШТАБ | D39.33, CURRENT-STATE | +| 54 | Масштаб целой книги: волны/каденс/потолки/ETA на сотнях глав (гоняли максимум 10; книга 7,78 млн симв., ~2284 раздела). ⚠ **Дописка инвентаря №18 (D39.147 п.2г):** жёстких потолков размера в коде НЕТ, но исходник читается в память целиком (`backend/internal/chunk/ingest.go:244`=`raw, err := os.ReadFile(p)` — ⚠ испр. 16.09: было :98), чтения стора беспагинационны под `opTimeout = 10s` (`backend/internal/store/store.go:39`=`var opTimeout = 10 * time.Second`) и бюджеты нарезки калиброваны на 25 главах (`backend/internal/config/pipeline.go:181`=`the 25-chapter rerun` — ⚠ испр. 16.09: было :126-138) — ни одно из трёх на 2283 главах не проверено ничем | бэкенд | когда-нибудь (последним по курсу) | МАСШТАБ | D39.33, CURRENT-STATE | | **— ПОЛИГОН (кандидаты пакетов) —** | | | | | | | 55 | **`dialogue_dash` мерить только на невиданном тексте** (подогнан под 蛊真人; цифры мини-прогона аргументом не считаются) ; расширено до вне-претрейн чекпоинта целиком: r-коэффициенты exp01/08 · precision чекеров · частота эха · чистовик exp15-выводов ; + arity-полоса паспорта (D29.2г): решить — dialogue_dash покрывает диалоговую половину или мерить (D39.73). **Частично закрыта эксп-21 (D39.117):** направление главного вывода воспроизведено на чистом en-материале (узнавание 1/5), $0-довесок исполнен частично; ⚠ **ПЕРЕ-СНЯТА 05.09 (D39.198 п.5): требования НОВОЙ книги здесь НЕТ.** Владелец: прогоняем на тех же текстах (мастер Гу и Жан-Кристоф), а «известность модели по претрейну» остаётся ОГРАНИЧЕНИЕМ ВЫВОДА — результат на классике читается как предварительный, и это пишется в вывод, а не покупается новой книгой. Прежняя редакция несла ЖЁСТКИЙ платный заказ полигону. **срез эксп-21 НЕ купил** (главный zh-замер на книге 4/5, без пинга) — остаток = **ОГОВОРКА В ВЫВОДЕ**, а не покупка: замер идёт на мастере Гу и Жан-Кристофе, а «модель знает текст по претрейну» пишется ограничением результата (⚠ испр. 05.09 — колонки продолжали заказывать неконтаминированный zh-срез уже ПОСЛЕ того, как шапка строки его сняла: полигон читает колонки) | полигон | когда-нибудь (оговорка вывода, не заказ) | формулировка в отчёте | D39.37(4), D39.40, D39.46, D39.108, **D39.117** | | 56 | Ёфикатор/санитайзер-классы не размечены (§6.5 отчёта пакета-6) | полигон | когда-нибудь | полигон-пакет | D39.46, CURRENT-STATE | @@ -172,7 +172,7 @@ | 127 | **Устаревший DDL-коммент `glossary.source`** (`migrate.go:194`: «seed|ruby|auto», фактические пути записи — seed/ruby/mined, `auto` не пишет никто; фантом уже утёк во фронт-доки дважды) — поправить коммент | бэкенд | когда-нибудь (попутно любым паком store) | однострочная правка | ревью контракта 04.08, D39.99 | | 106 | **Слой 3: целевой контракт «узкие мандаты + ДИФФЫ» против текущего full-regen — гейт «перепроверить до стройки» в силе, приоритет ПОНИЖЕН (D39.117: full-regen выигрывает у ремонта; оговорка полигона — чинил дешёвый фиксер по предложению, не сильный редактор узким мандатом).** Реактивация — только через эту строку. Археология дословно (эмпирика D39.108 · история дыры учёта) — `architecture/13-tech-debt-anchors.md` §Б-106 | владелец → бэкенд | когда-нибудь (пере-проверка «сильный редактор × узкий мандат» — перед стройкой слоя 3) | замер → решение владельца | 09 §Слой 3, D39.90, D39.108, **D39.117** | | 114 | **Конфиго-слой ручки эффорта: два дешёвых хвоста приёмки (вне снапшота, $0 прогонов).** (а) **Д4 отчёта:** `gates.terminology.target_script` НЕ сверяется с `book.target_lang` — `target_lang: ru` + `target_script: Latin` грузится чисто и **ИНВЕРТИРУЕТ** банковский экран (ловит целевой, пропускает чужой); сверка при загрузке против `lang.LangScripts(TargetLang)` — тот же дата-план, что у экрана строки 46, громкий отказ на несовпадении. (б) **Находка-2 приёмки:** стейл-доккоммент `capability.go:78` — у константы `ReasoningExtraBodyDisable` до сих пор «effort "" leaves the provider default», противореча проводу (`applyToBody` мержит disable на `""`, комментарий в теле arm это прямо объясняет) и починенному `ThinksOnWire`; однострочник тем же касанием ⚠ **(в) дописка 07.09:** зеркало `ThinksOnWire` ↔ `applyToBody` не пиньётся ни одним кейсом (мутация арма оставляет батарею зелёной при разъехавшемся зеркале) — при следующем касании файла делегация в `Capability.SuppressesThinking`, ~40 строк, снапшот-нейтрально: `snapshot.go:535` фолдит JSON-форму `llm.Capability`, а не её методы (research/33 Д2) | бэкенд | скоро (мелкий пак или попутно со строкой 46) | правка Go, снапшот не двигает | D39.91, EFFORT_HANDLE Д4 | -| 115 | **`//go:embed` целевых данных — ЯВНЫЙ список файлов: новая ЦЕЛЬ требует правки Go (Д6 отчёта).** `internal/lang/embedded.go:22`=`//go:embed data/cjk-section.txt` перечисляет файлы поимённо, `CompileCheckers` паникует при неполном файле цели ⇒ на канон-вопрос «заработает ли пара, которой в репо НЕТ, без правки Go» ответ сегодня **НЕТ** — дыра в ратифицированной «ФАЗЕ 2 ОБЩНОСТИ ✅» (D39.64), и она не про язык, а про строку эмбеда. Решить форму: `embed data/*` (и как манифест фолдится в `EmbeddedVersion`, чтобы НЕ перекупать чужие пары) против явного списка как осознанного гейта полноты данных цели | оркестратор → бэкенд | когда-нибудь (триггер: первая новая целевая пара; учтён в реестре 108) | отдельное решение | D39.91, EFFORT_HANDLE Д6, D39.64 | +| 115 | **`//go:embed` целевых данных — ЯВНЫЙ список файлов: новая ЦЕЛЬ требует правки Go (Д6 отчёта).** `backend/internal/lang/embedded.go:22`=`//go:embed data/cjk-section.txt` перечисляет файлы поимённо, `CompileCheckers` паникует при неполном файле цели ⇒ на канон-вопрос «заработает ли пара, которой в репо НЕТ, без правки Go» ответ сегодня **НЕТ** — дыра в ратифицированной «ФАЗЕ 2 ОБЩНОСТИ ✅» (D39.64), и она не про язык, а про строку эмбеда. Решить форму: `embed data/*` (и как манифест фолдится в `EmbeddedVersion`, чтобы НЕ перекупать чужие пары) против явного списка как осознанного гейта полноты данных цели | оркестратор → бэкенд | когда-нибудь (триггер: первая новая целевая пара; учтён в реестре 108) | отдельное решение | D39.91, EFFORT_HANDLE Д6, D39.64 | | 108 | **Реестр ЗАГЕЙЧЕННЫХ ТРИГГЕРОВ (триггер → что вернётся → источник) — ВЫСЕЛЕН ДОСЛОВНО в `architecture/13-tech-debt-anchors.md` §Б-108; сверять на каждом переходе горизонта (норма D39.66 «каждое отложено получает носитель» в силе).** ⚠ Живое оттуда: go.work-триггер УЖЕ наступил (`platform/go.mod` заведён) — ⚠ **тот же факт несёт строка 237(а), испр. 05.09: чинится ОДИН раз и там, здесь он ЗАПИСЬ РЕЕСТРА, а не заказ** · вахта маппинга эффорта dspro «early August 2026» · движение тулчейна к go1.27 ⇒ строка 119 ПЕРВОЙ | оркестратор | скоро ($0, гигиена трекера) | завести реестр + сверку в норму лендинга | D39.66, D39.90 | | 109 | **Продуктовые требования без строки-носителя: ПТ-6 (структура абзацев) · ПТ-7 (слабый оригинал — вопрос владельца) · ПТ-22 (продуктовый интейк настроек) · ПТ-10 (механизм веб-фетча).** Носители заводить при первом касании тем; реестр `product-requirements.md` первичен. Разбор дословно — `architecture/13-tech-debt-anchors.md` §Б-109 | оркестратор/владелец | скоро ($0 — расписать носители) | завести строки/вопросы → диспозиции | D39.90, product-requirements | | 110 | **Детектор повторов лемм / защита авторских рефренов** (`04-unhappy-paths.md:97,130 п.5`): $0-минимум исполнен промптом (editor.md, пакет-чекеров 02.08), механизм явно не строился — «нет размеченного класса; связка с alignment/Bertalign». Строки-носителя не было; предмет живой, потому что отличить дефектный повтор от авторского рефрена без выравнивания нельзя | бэкенд/полигон | когда-нибудь (с корпусом пилота, строка 85) | размеченный класс → решение | 04-unhappy §5, D39.90 | @@ -191,7 +191,7 @@ | 225 | **Гейт «строка `open`, а лекарство уже в дереве».** При лендинге пересекать ПОЛНЫЕ пути застейдженных файлов с якорями открытых строк регистра и бэклога; совпадение — вопрос лендеру, а не находка следующего пака. Замерено прежде решения: по именам файлов 22 совпадения, почти все ложные; по полным путям 2, оба настоящие, и один из них (`PD-157`) убил мой же лендинг `d1eb8a9`. Норма-половина уже стоит в `platform/docs/ENGINEERING_STANDARDS.md` §3 п.8; здесь — машинная половина, режимом `counts.py` | оркестратор | скоро (окупился до постройки) | режим `counts.py`, берущий список путей и печатающий открытые строки, чьи якоря в них целят | приёмка пака P8-REVIEW 27.08, D39.159 п.7 | | 226 | **История ПРЕДЪЯВЛЕННОГО не ведётся — «почему меня не остановило на этом термине» ответить нечем.** Карта и человеческая таблица стопа перезаписываются каждым прогоном, память флажка — плоское множество поверхностей без `map_id` и без времени. Это прямая расплата за то, что стоп срабатывает ОДИН раз (кластерная память, названный остаток дофикса-2), и единственная возможная диагностика спора. Кандидат в пак решённости, не заказ. ⚠ Шестое, названное консилиумом и оставленное владельцу: авторство и время решения — сегодня цена нуля (владелец один), станет нужным при мультипользовательской платформе, и тогда его захотят ЗАДНИМ ЧИСЛОМ | бэкенд | скоро (диагностики нет вовсе) | движок метит предъявленное `map_id` и временем; оверлей отвечает «что предъявлялось на прошлом стопе» | консилиум по читающей стороне банка 27.08 | | 250 | **Заголовок глоссария на проводе ОПИСЫВАЕТ маркер, которого после пака больше нет — живая строка с висячей ссылкой.** Строка данных `ru glossary_header` (`backend/internal/lang/data/injection.txt`) дословно объясняет модели: «строки с пометкой ⟨проверить⟩ — неподтверждённые кандидаты», а пункт 3 вайр-батча снимает маркер с провода по `D39.104` п.2 ⇒ на проводе не останется НИ ОДНОЙ помеченной строки, а заголовок продолжит объяснять пометку. ⚠ Это НЕ мёртвая строка данных (те — `editor_unverified_header` и `unverified_marker`, они просто перестают читаться), это ЖИВАЯ строка, которую читает модель. По `D39.104` п.1 клаузула становится ВАКУУМНОЙ, а не ложной, вред не измерен — поэтому не блокер. ⛔ **Чинится ТОЛЬКО правкой `injection.txt`, а она двигает `EmbeddedVersion` → `cutTag` → ключ манифеста → снос `unit_resolutions` книги (строка 198).** Носитель — ближайшее ОКНО правки эмбед-данных: строка **160** идёт своим паком и всё равно бампает форму манифеста. Найдено бэкенд-сессией вайр-батча 04.09 — она правильно НЕ тронула и принесла предмет | бэкенд | скоро (в окне строки 160) | правка `injection.txt` в окне 160 | пинг бэкенд-сессии 04.09 | -| 251 | **Банковый контур в `pipeline-c1.yaml` требует АРТЕФАКТА, которого в git нет и быть не должно — первая же выкатка после лендинга откажется стартовать, если его не положили.** ⚠ **УТОЧНЕНО 08.09 живым прогоном — ЭТО ДВА РАЗНЫХ ДЕФЕКТА С РАЗНЫМ ЛЕЧЕНИЕМ, и прежняя формулировка сливала их в один.** (1) Путь `contrast_path` В КОНФИГЕ ЗАДАН, файла нет ⇒ `os.Open` (`backend/internal/pipeline/mining.go:69`=`os.Open(r.Pipeline.Mining.ContrastPath)`) — отказ ГРОМКИЙ, с флагом `--verify-bank` и без него; боевой c1 путь задаёт, значит это «развёртывание не поднимется». (2) ⛔ **СНЯТО 08.09 — Я СДЕЛАЛ ЭТУ СТРОКУ ХУЖЕ, ЧЕМ ОНА БЫЛА.** Вчера сюда попало «на конфиге без `contrast_path` контур МОЛЧА МЁРТВ» — неверно для конфигурации, которая одна и имеет значение: `backend/internal/config/pipeline.go:1160`=`gates.repair.model %q is not defined` (⚠ испр. 17.09: было :1152) ОТКАЗЫВАЕТ загрузку, если `gates.terminology.enabled` и путь пуст, и стоит это с **04.09** (`b8154cd`) — на четыре дня раньше моей «правки»; второй вход закрыт `runner.go:349`. Тихий `return false, nil` в `backend/internal/pipeline/mining.go:58-66`=`r.Pipeline.Mining.ContrastPath == ""` достижим только при ВЫКЛЮЧЕННОМ гейте, то есть когда контур и не заказан. Рантбук требование несёт (`platform/deploy/README.md`, 8 упоминаний). ⚠ Класс ошибки: принял формулировку зоны, проверил ОДИН путь по коду и не спросил, достижим ли он при живом конфиге. **Живой остаток строки другой** — пар-перекос: `mining.contrast_path` есть факт ИСХОДНОГО языка в пар-агностичном конфиге (задан в 3 из 5 конфигов `backend/configs/`), то есть это цель №2, а не «выкатка не поднимется». ⇒ лечение (1) — положить артефакт при выкатке; лечение (2) — сделать отсутствие контура ВИДИМЫМ без флага. Подтверждено чтением кода оркестратором и живым прогоном зонной сессии 08.09, которой пришлось воспроизводить артефакт по запиненному рецепту `docs/experiments/16-bank-mining.md` (sha сошёлся), потому что на машине его нет. Оба банк-роля живут ВНУТРИ стопа майнинга, а `runBankMiningStop` (`backend/internal/pipeline/mining.go:58`=`func (r *Runner) runBankMiningStop`) возвращается РАНЬШЕ построения кандидатов при пустом `mining.contrast_path` ⇒ без корпуса контраста терминолог и классификатор не исполняются ВООБЩЕ, чем бы ни были заполнены их гейты. Артефакт — общечастотный словарь jieba (`.gitignore:38`: «jieba 0.42.1 dict.txt, 5MB — SHA pinned in the report, **reproducible**»), рецепт и sha256 `7197c321…` — `docs/experiments/16-bank-mining.md` (греп `jieba_dict_general_zh`). ⚠ **Риск ограничен и это ГЛАВНОЕ:** артефакт не утерян, а ВОСПРОИЗВОДИМ по запиненному рецепту; дыра в том, что требование не доехало до РАНТБУКА развёртывания (`platform/deploy/README.md` о нём не знает), и оператор узнаёт о нём только от гарда. Гарды поставлены паком и они правильные: загрузка ОТКАЗЫВАЕТ при включённом гейте с пустым ключом, наличие файла проверяется на ПИШУЩЕМ пути рядом с `CheckKeys` — то есть до оплаченной черновой волны, а не после неё. ⛔ **Что делать:** требование в рантбук платформы (её зона, пинг) + слово владельца/оператора, что файл лежит на боевой машине, ДО первой выкатки после лендинга. ⚠ **Вторая половина, вскрытая тем же включением:** корпус контраста — факт ИСХОДНОГО ЯЗЫКА, а `mining.contrast_path` живёт в конфиге пайплайна, который по построению пар-агностичен (цель проекта №2). Перекос не заведён паком, а вскрыт им; пара, которой в репо нет, потребует своего корпуса и своего ключа | бэкенд+платформа | скоро (до первой выкатки после лендинга вайр-батча) | пинг рантбуку + слово оператора; пар-перекос — отдельным решением | бэкенд-сессия вайр-батча 04.09 | +| 251 | **Банковый контур в `pipeline-c1.yaml` требует АРТЕФАКТА, которого в git нет и быть не должно — первая же выкатка после лендинга откажется стартовать, если его не положили.** ⚠ **УТОЧНЕНО 08.09 живым прогоном — ЭТО ДВА РАЗНЫХ ДЕФЕКТА С РАЗНЫМ ЛЕЧЕНИЕМ, и прежняя формулировка сливала их в один.** (1) Путь `contrast_path` В КОНФИГЕ ЗАДАН, файла нет ⇒ `os.Open` (`backend/internal/pipeline/mining.go:69`=`os.Open(r.Pipeline.Mining.ContrastPath)`) — отказ ГРОМКИЙ, с флагом `--verify-bank` и без него; боевой c1 путь задаёт, значит это «развёртывание не поднимется». (2) ⛔ **СНЯТО 08.09 — Я СДЕЛАЛ ЭТУ СТРОКУ ХУЖЕ, ЧЕМ ОНА БЫЛА.** Вчера сюда попало «на конфиге без `contrast_path` контур МОЛЧА МЁРТВ» — неверно для конфигурации, которая одна и имеет значение: `backend/internal/config/pipeline.go:1274`=`gates.repair.model %q is not defined` (⚠ испр. 17.09: было :1152) ОТКАЗЫВАЕТ загрузку, если `gates.terminology.enabled` и путь пуст, и стоит это с **04.09** (`b8154cd`) — на четыре дня раньше моей «правки»; второй вход закрыт `runner.go:349`. Тихий `return false, nil` в `backend/internal/pipeline/mining.go:58-66`=`r.Pipeline.Mining.ContrastPath == ""` достижим только при ВЫКЛЮЧЕННОМ гейте, то есть когда контур и не заказан. Рантбук требование несёт (`platform/deploy/README.md`, 8 упоминаний). ⚠ Класс ошибки: принял формулировку зоны, проверил ОДИН путь по коду и не спросил, достижим ли он при живом конфиге. **Живой остаток строки другой** — пар-перекос: `mining.contrast_path` есть факт ИСХОДНОГО языка в пар-агностичном конфиге (задан в 3 из 5 конфигов `backend/configs/`), то есть это цель №2, а не «выкатка не поднимется». ⇒ лечение (1) — положить артефакт при выкатке; лечение (2) — сделать отсутствие контура ВИДИМЫМ без флага. Подтверждено чтением кода оркестратором и живым прогоном зонной сессии 08.09, которой пришлось воспроизводить артефакт по запиненному рецепту `docs/experiments/16-bank-mining.md` (sha сошёлся), потому что на машине его нет. Оба банк-роля живут ВНУТРИ стопа майнинга, а `runBankMiningStop` (`backend/internal/pipeline/mining.go:58`=`func (r *Runner) runBankMiningStop`) возвращается РАНЬШЕ построения кандидатов при пустом `mining.contrast_path` ⇒ без корпуса контраста терминолог и классификатор не исполняются ВООБЩЕ, чем бы ни были заполнены их гейты. Артефакт — общечастотный словарь jieba (`.gitignore:38`: «jieba 0.42.1 dict.txt, 5MB — SHA pinned in the report, **reproducible**»), рецепт и sha256 `7197c321…` — `docs/experiments/16-bank-mining.md` (греп `jieba_dict_general_zh`). ⚠ **Риск ограничен и это ГЛАВНОЕ:** артефакт не утерян, а ВОСПРОИЗВОДИМ по запиненному рецепту; дыра в том, что требование не доехало до РАНТБУКА развёртывания (`platform/deploy/README.md` о нём не знает), и оператор узнаёт о нём только от гарда. Гарды поставлены паком и они правильные: загрузка ОТКАЗЫВАЕТ при включённом гейте с пустым ключом, наличие файла проверяется на ПИШУЩЕМ пути рядом с `CheckKeys` — то есть до оплаченной черновой волны, а не после неё. ⛔ **Что делать:** требование в рантбук платформы (её зона, пинг) + слово владельца/оператора, что файл лежит на боевой машине, ДО первой выкатки после лендинга. ⚠ **Вторая половина, вскрытая тем же включением:** корпус контраста — факт ИСХОДНОГО ЯЗЫКА, а `mining.contrast_path` живёт в конфиге пайплайна, который по построению пар-агностичен (цель проекта №2). Перекос не заведён паком, а вскрыт им; пара, которой в репо нет, потребует своего корпуса и своего ключа | бэкенд+платформа | скоро (до первой выкатки после лендинга вайр-батча) | пинг рантбуку + слово оператора; пар-перекос — отдельным решением | бэкенд-сессия вайр-батча 04.09 | | 252 | **Две гарантии не прибиты — мутации сессии ПЕРЕЖИЛИ всю батарею** (собственные посадки бэкенд-сессии вне шести пунктов заказа, 04.09; из восьми посадок шесть красные, две выжили и НЕ чинились как вне-заказные). **(а) `StickyDepth = 2 → 1` не ловит НИКТО** — глубина окна липкости меняется молча. **(б) `priorityRank`, отбрасывающий приоритет доверия** (подтверждённые строки раньше неоднозначных в бюджете инъекции), **не ловит НИКТО** — то есть порядок, решающий, ЧТО попадёт в инъекцию при нехватке бюджета, можно перевернуть безнаказанно. ⚠ Класс тот же, что дал паку «число согласия» три неприбитых свойства: заявленное поведение без пинящего теста. Сессия правильно НЕ чинила вне заказа и принесла предмет | бэкенд | скоро (ближайшим касанием инъекции) | по тесту на гарантию + запись в `cmd/tmmutate/mutations.json` | собственные посадки бэкенд-сессии 04.09 | | 253 | ⚠ **ДВИЖКОВАЯ ПОЛОВИНА ЗАКРЫТА 08.09 (`D39.228`): полнота консолидации доезжает до сайдкара и до stdout-экрана подписи. ОСТАЁТСЯ ПЛАТФОРМЕННАЯ — поля на `BankPage` нет, читателей у секции `consolidation` НОЛЬ**, и до её лендинга это сознательно заведённый класс A онтологии банка (⛔ бит `complete` платформа берёт ГОТОВЫМ, не выводит у себя: у движка он считается от среза РЕНДЕР-паса, а срез классификатора полноты банка не означает). ⚠ испр. 08.09: акт `D39.228` объявил строку закрытой ЦЕЛИКОМ — неверно, лечение (б) по телу ниже требует «полнота в сайдкар + поле на `BankPage`», и вторая половина не построена. Ниже — тело находки. **НА ЭКРАНЕ ПОДПИСИ БАНКА ПОДПИСЫВАТЬ НЕЧЕГО, а сам подписываемый банк НЕПОЛОН — две половины одного шва, найдены ПЕРВЫМ живым прогоном 04.09.** **(а)** ⚠ **ЭТО ТОТ ЖЕ ДЕФЕКТ, ЧТО СТРОКА 224 — испр. 05.09:** корень там уже найден и назван (майненные строки пишутся внутри ветки `if !stopping`), поэтому «разобрать порядок публикации» здесь заказывать НЕЛЬЗЯ — работа удвоится. Половина (а) закрывается лендингом 224; живой в этой строке остаётся только (б). Прогон встал `awaiting_bank`, `GET /bank` отдал `total 0, signed 0` — при том что рядом лежали `mined-signature.yaml` 49 КБ и `bank-stop.txt` 60 КБ, а движок держал 82 неразобранные поверхности; термины появились в read-модели только на СЛЕДУЮЩЕМ прогоне (`bank export refreshed … terms=83`). Платформа читает сайдкар честно: 0 значит 0 ⇒ либо сайдкар пишется не в тот момент, либо стоп наступает РАНЬШЕ публикации банка. Корень скорее движковый. **(б)** Банк, который пользователь подписывает, ЧАСТИЧНО КОНСОЛИДИРОВАН, и платформа об этом не знает вовсе: терминология урезала план под бюджет ДО первого вызова (`batches_dropped=5`, `consolidated=38 declined=0 unanswered=47` из 85), а поверхности нет ни одной — `grep -rn 'consolidat\|unanswered\|batches_dropped' platform/internal/ --include=*.go` → **0**, аллоулист сайдкара несёт только термины. ⇒ **пользователь подписывает как ПОЛНЫЙ банк то, что движок сам называет неполным.** Лечение (б) — КАНАЛ: полнота консолидации в сайдкар + поле на `BankPage`; лечение (а) — разбор порядка «стоп против публикации». ⚠ Обе половины на шве, чинятся согласованно | бэкенд+платформа | скоро (до первого внешнего пользователя) | разбор порядка публикации + канал полноты | наблюдение платформы за живым потоком 04.09, H10/H11 | | 254 | **Шесть движковых ловушек, увиденных ПЕРВЫМ живым прогоном (04.09) и НЕ тронутых платформой — чужая зона.** ⚠ **ОДНА ИЗ ШЕСТИ РЕШЕНА ВЛАДЕЛЬЦЕМ 05.09 — остальные ПЯТЬ живы, строку не закрывать** (испр. 05.09; строка 285 закрывает ровно эту одну и не больше). ⛔ Решённая — самая дорогая: `manifest` на пустом файле даёт exit 11, а интейк на 11 УДАЛЯЕТ ЗАГРУЗКУ ⇒ пользователь, приславший пустой файл, терял его. **Лечение названо владельцем: fail fast на загрузке** — строка **285**. · `tmctl build` не читает контекст: всегда SIGKILL, staging-файл `.tmp-*` остаётся · потолок бросает летящие вызовы, они списываются нулём (`PD-441`, замер: отмены на 120756/156469/156470 мс) · терминология МОЛЧА режет план под бюджет (вход строки 253б) · сайдкар банка пуст в момент стопа (вход 253а) · **`build --format X` без `--out` удаляет соседние форматы** — ловушка для оператора с руками. ⚠ Ни один из шести не найден чтением кода за месяцы — все шесть увидены за один прогон | бэкенд | скоро (ближайшим касанием соответствующего пути) | по пунктам; часть — райдерами других паков | наблюдение платформы за живым потоком 04.09, H21 | @@ -248,7 +248,7 @@ | 313 | ⚠ **НОСИТЕЛЬ ПОЯВИЛСЯ 07.09 (`D39.225`): цель `make mutations` гоняет подмножество каталога (14 из 225) на копии дерева и печатает свип якорей СО ЗНАМЕНАТЕЛЕМ (`0 of 225 rotten`) при каждом прогоне, зелёном тоже. Вне `battery` намеренно: пере-замер 07.09 дал 123 % её времени и гейт идёт без `-race`. ОСТАЁТСЯ: остальные 211 записей по-прежнему проверяются только на живость цели.** ⛔ **КАТАЛОГ МУТАЦИЙ ДОКАЗЫВАЕТ, ЧТО МУТАЦИЯ СУЩЕСТВУЕТ, А НЕ ЧТО ОНА ЛОВИТСЯ.** Из **211** записей каталога регулярно гоняются единицы (в паке структуры глав — 14, целящие в изменённое поведение); остальные проверяются только на ЖИВОСТЬ ЦЕЛИ грепом. ⇒ зелёный каталог говорит «посадка на месте», а читается как «посадка краснит». **Тот же класс, что `D39.214` п.3: доказано одно, сказано про другое.** ⚠ Носителя у этого НЕ БЫЛО ни строкой, ни рядом — проверено грепом по живому бэклогу 06.09 по прямому вопросу оркестратора; ближайшая строка 252 говорит о ДВУХ конкретных выживших посадках 04.09 и о полном прогоне не говорит ничего. ⭐ **Третий за час случай, когда находка жила только в письме** (первые два — находки платформы без рядов и нечитаемое оглавление строки 312): **находка без носителя не находится.** ⇒ заказ: либо каталог гоняется целиком по расписанию, либо его зелень перестаёт называться доказательством ловли — формулировку выбирает зона, но молча оставлять нельзя. ⚠ Назвал СТРОИТЕЛЬ про собственный пак, единственным из пяти своих сомнений, что закрыл бы ДО продажи ⚠ **Цена полного прогона ЗАМЕРЕНА 06.09, и отсрочка обоснована ею, а не удобством:** 126 записей из 211 гоняют `internal/pipeline` по ~3 минуты ⇒ полный прогон **6+ часов**. При этом 197 непрогнанных — УНАСЛЕДОВАННЫЕ, каждая краснела у заводившей смены. ⇒ это стоячая гигиена, а не крит; зона прямо отказалась изображать закрытие шестичасовым прогоном «вдруг что-то протухло» | бэкенд | когда-нибудь | зелень каталога означает пойманную мутацию, а не существующую запись | **D39.214** | | 314 | ⛔ **РАЗРЕЗ ПРОВЕРЯЕТСЯ ТОЛЬКО НА НЕИЗМЕННОСТЬ — НА ПРАВИЛЬНОСТЬ ЕГО НЕ ПРОВЕРЯЕТ НИЧТО.** Ни один гейт, тест или замер не отвечает на вопрос «верны ли ЭТИ границы»: гейт сравнивает «до» и «после», оракул сверяет два прибора движка МЕЖДУ СОБОЙ. ⚠ **Инвариант сохранения доказывает СОХРАННОСТЬ и молчит о КОРРЕКТНОСТИ** — он считает разбиение (каждый читаемый документ либо исключён намеренно, либо ровно в одной группе) и сходится ОДИНАКОВО при верной и при неверной группировке, если та ничего не теряет. ⇒ «инвариант сошёлся на трёх живых книгах» доказывает сохранность, а читается как корректность разреза. Что 71 глава для Kristoff — ВЕРНО, не показал никто; показано лишь, что так говорит его `nav`. **Тот же класс, что `D39.214` п.3: доказано одно, сказано про другое.** ⭐ Назвал СТРОИТЕЛЬ про собственный пак, найдя это в своих же утверждениях, а не в чужих. ⚠ **Измеримая часть ЗАМЕРЕНА 06.09 и расхождения не дала:** «совпадает ли отданный разрез с тем, что книга ОБЪЯВЛЯЕТ» — по трём книгам 193 цели оглавления, **все на уровне документа, ни одной внутрь документа** (Kristoff 71 · isekai 88 · fifty_shades 34) ⇒ там, где объявленное можно сверить механически, оно сходится. **Остаётся ровно некруговая часть: верно ли то, что объявляет сам `nav`** — она требует человеческого суждения и не закрывается ни тестом, ни прибором. ⇒ **строка стоит не как задача, а как признанная ГРАНИЦА** | бэкенд | когда-нибудь | есть носитель, отвечающий «верны ли границы», а не только «не изменились ли они» | **D39.214** | -| 315 | ✅ **ЗАКРЫТА ЗАМЕРОМ 06.09 — ПРОШЛА.** Блокер («промтов пары `en-ru` нет») снят БЕЗ нарушения запрета: у пар-конфига есть ручка `prompts_root` (`backend/internal/config/pair.go:33`=`PromptsRoot string`, проверено мной), и корень промтов-заглушек собран ВНЕ репозитория — в дереве не создано ничего, промт-пака пары как не было, так и нет. **Замер зоны, `tmctl manifest`, EXIT 0, $0:** `structure: declared` · 71 глава / 351 юнит / 356 чанков · `manifest_version` НЕ сдвинут · нумерация плотная 1..71 без дыр и дублей, `number: null` — ноль · id глав уникальны · **`title_raw` на проводе 71 из 71**, настоящие · ценовая проекция на всех трёх уровнях, глав без цены ноль. ⭐ **И то, что видно только на живой НЕ-CJK книге: `heading` пуст у ВСЕХ глав** (шаблона для пары нет), **а `title_raw` заполнен** ⇒ единственное, что несёт название главы для этой книги, — поле, которое построил этот пак. Обоснование §2.5 стало замером, а не доводом. ⚠ Числа — зоны, на её стенде; механизм обхода блокера и чистоту дерева проверил я. ⛔ Прежняя формулировка: **МАНИФЕСТНАЯ ПОЛОВИНА EPUB НЕ ПРОХОДИЛА НИ РАЗУ НА ЖИВОЙ КНИГЕ.** `tmctl manifest` на EPUB владельца не идёт — промтов пар `en-ru`/`ja-ru` не существует, и пак структуры глав чинить это не заказывал. ⇒ `title_raw` на проводе, id глав и ЦЕНОВАЯ ПРОЕКЦИЯ для EPUB держатся **исключительно на фикстурах авторства самой зоны**; книги владельца мерены только на уровне ингеста. ⚠ **Первая же платная EPUB-книга пойдёт по пути, который на живой книге не проходил никогда** — и это ДЕНЬГИ, а не удобство. ⭐ Стоит в отчёте зоны §6, но отчёт не трекер: через месяц его никто не откроет — ровно довод, которым эта строка и заведена | бэкенд+полигон | скоро | манифестная половина EPUB пройдена на живой книге хотя бы раз | **D39.214** | +| 315 | ✅ **ЗАКРЫТА ЗАМЕРОМ 06.09 — ПРОШЛА.** Блокер («промтов пары `en-ru` нет») снят БЕЗ нарушения запрета: у пар-конфига есть ручка `prompts_root` (`backend/internal/config/pair.go:34`=`PromptsRoot string`, проверено мной), и корень промтов-заглушек собран ВНЕ репозитория — в дереве не создано ничего, промт-пака пары как не было, так и нет. **Замер зоны, `tmctl manifest`, EXIT 0, $0:** `structure: declared` · 71 глава / 351 юнит / 356 чанков · `manifest_version` НЕ сдвинут · нумерация плотная 1..71 без дыр и дублей, `number: null` — ноль · id глав уникальны · **`title_raw` на проводе 71 из 71**, настоящие · ценовая проекция на всех трёх уровнях, глав без цены ноль. ⭐ **И то, что видно только на живой НЕ-CJK книге: `heading` пуст у ВСЕХ глав** (шаблона для пары нет), **а `title_raw` заполнен** ⇒ единственное, что несёт название главы для этой книги, — поле, которое построил этот пак. Обоснование §2.5 стало замером, а не доводом. ⚠ Числа — зоны, на её стенде; механизм обхода блокера и чистоту дерева проверил я. ⛔ Прежняя формулировка: **МАНИФЕСТНАЯ ПОЛОВИНА EPUB НЕ ПРОХОДИЛА НИ РАЗУ НА ЖИВОЙ КНИГЕ.** `tmctl manifest` на EPUB владельца не идёт — промтов пар `en-ru`/`ja-ru` не существует, и пак структуры глав чинить это не заказывал. ⇒ `title_raw` на проводе, id глав и ЦЕНОВАЯ ПРОЕКЦИЯ для EPUB держатся **исключительно на фикстурах авторства самой зоны**; книги владельца мерены только на уровне ингеста. ⚠ **Первая же платная EPUB-книга пойдёт по пути, который на живой книге не проходил никогда** — и это ДЕНЬГИ, а не удобство. ⭐ Стоит в отчёте зоны §6, но отчёт не трекер: через месяц его никто не откроет — ровно довод, которым эта строка и заведена | бэкенд+полигон | скоро | манифестная половина EPUB пройдена на живой книге хотя бы раз | **D39.214** | | 316 | **У ЭРРАТ НЕТ РЕЕСТРА, И ЧИТАТЕЛЬ НОТЫ НЕ МОЖЕТ УЗНАТЬ, КАКИЕ ИЗ НИХ К НЕЙ ОТНОСЯТСЯ, НЕ ПРОЧТЯ ВСЕ.** Замер верификатора 06.09: эррат в шапке **53**, из них 06.09-* — **10**; на `D39.212` их три, на `D39.211` две, на `D39.213` две; длина одной — **929–4020 знаков ОДНОЙ строкой**. ⇒ **чтобы прочесть `D39.212` верно, надо прочесть 7912 знаков эррат при теле акта около 5000 — корректирующего текста БОЛЬШЕ, чем корректируемого**, и цепочка уже глубиной два (`06.09-ж` правит `06.09-г`). ⚠ **Дефект НЕ в объёме правок:** след — это ровно то, ради чего смена стоила своих денег, и все сегодняшние нормы выводимы только из него (что заявлено, кем опровергнуто, чем). Дефект в том, что **у нот реестр есть (`docs/architecture/05-decisions-index.md`), а у эррат нет ничего.** ⇒ дешёвая форма, названная верификатором: строка реестра получает колонку «живые эрраты», `counts.py` её сверяет — тот же класс, что восьмой гард итога регистра: **не помнить, а проверять**. ⚠ **Отложено сознательно, а не забыто:** это седьмая правка прибора за смену, а предыдущие шесть трижды потребовали починки после приёмки; менять гейт на исходе смены — ровно та спешка, которой этот бэклог посвящён | оркестратор | скоро | к ноте один хоп даёт список живых эррат, и его сверяет гейт | **D39.202** | | 317 | **У ЧИСЛА, СТОЯЩЕГО В КАНОНЕ, НЕТ ПРИБОРА В РЕПОЗИТОРИИ.** `D39.214` п.6 цитирует замер «сканер по 193 свойствам схем канона, три правила, семь флагов, пять ложных, два настоящих». **Сканер не закоммичен** — проверено грепом 06.09. ⇒ ни «193», ни «семь» не воспроизводимы никем, включая автора. ⛔ **ПОДОЗРЕНИЕ НА НЕПОЛНОТУ СКАНА СНЯТО 06.09 — И СНЯЛ ЕГО ТОТ, КТО ПРИНЁС.** Сначала агент верификатора пере-выполнил три правила по описанию и получил **двенадцать** флагов; это читалось как «зона что-то не досмотрела». Верификатор довёл зацепку до замера сам: **189 свойств, 9 уникальных флагов** — ровно зонные ПЯТЬ ложных плюс `Chapter.number` (настоящая находка, уже диспозиционированная) плюс три `EventStatus.*_reason`, **которые оказались дефектом ЕГО реализации**: правило читало `description` самого поля и не читало РОДИТЕЛЬСКИЙ объект, документирующий все три разом (`docs/architecture/14-api-contract/openapi.yaml:3472`=`unless its own status` (⚠ испр. 17.09: было :3168)). ⇒ **знание там не расщеплено, а централизовано — сказано один раз на три поля, и это лучше, чем трижды.** Семёрка зоны ВЕРНА, пропущенного нет. ⚠ И `OrderOptions.structure` прибор больше не флагует — потому что зона его починила. ⇒ **дефект этой строки — НЕВОСПРОИЗВОДИМОСТЬ числа, а не его неверность**, и срочность соответствующая. ⭐ **Та же форма, что норма «число называет ДЕРЕВО и ПОПУЛЯЦИЮ», только про ИНСТРУМЕНТ:** одноразовый скрипт, давший число в канон, обязан ехать в репозиторий вместе с числом — иначе замер неотличим от утверждения. ⇒ заказ: либо сканер ложится в `platform/` (или `docs/scripts/`) и число пере-снимается им, либо число в каноне помечается как невоспроизводимое. ⚠ Принёс верификатор ПОСЛЕ своего «ок», прямо сказав «это зацепка, а не находка, и опровержением зоны я это не считаю» | платформа+оркестратор | когда-нибудь | число в каноне пере-снимается прибором, лежащим в дереве | **D39.214** | @@ -273,10 +273,10 @@ | 342 | **ВОССТАНОВЛЕНИЕ ИЗ БЭКАПА НЕ ПРЕДЪЯВЛЕНО НА МАСШТАБЕ.** Предъявлено на малых данных; не проверено на книге в сотни мегабайт, при заполненном диске и при чужих открытых соединениях. `PD-462` покрывает СОСЕДНИЙ класс, этот — нет. ⚠ Бэкап, не проверенный на условиях, в которых он понадобится, — это не бэкап, а намерение | платформа | скоро | восстановление предъявлено на большой книге, полном диске и чужих соединениях | вопросы платформы 07.09 | | 343 | **`counts.py` ДЕРЖИТ РЕГИСТР ОДНИМ ПУТ�ём И НЕ ГЛОБИТ СЛАЙСЫ — предусловие нарезки `DEFECT_REGISTER.md`.** Вынос без этого молча уронит счёт открытых рядов, а гейт чисел покажет зелень: он читает ровно один файл. ⚠ План нарезки живёт в `docs/DOC_CLEANUP_PLAN.md` (Б14в) | доки | скоро | прибор читает регистр и его слайсы, счёт не меняется при выносе | вопросы платформы 07.09 | | **— ТЕХДОЛГ БЭКЕНДА: разбор research/33 (D39.224) —** | | | | | | -| 346 | ⚠ **ПОЛОВИНА (а) ЗАКРЫТА 07.09 (`D39.225`): пин расхождения и паритет-тест стоят, оба под мутациями. ОСТАЁТСЯ (б) — фикс в окне перенарезки.** ⛔ **ПРАВИЛО ЗАГОЛОВКА РАЗЪЕХАЛОСЬ ПО ТРЁМ ПРЕДИКАТАМ, И «第零章» ЛОМАЕТ ПРОЛОГ — две половины с РАЗНОЙ ценой.** Страж длины живёт только в ингесте (`chunk/ingest.go:307`=`const chapterHeaderMaxRunes = 60` `chapterHeaderMaxRunes = 60`, применён `:323`; в `chunker.go` `RuneCountInString` — 0 хитов), осмысленность номера — только в чанкере (`backend/internal/chunk/chunker.go:315-317`=`v := section + num` — ⚠ испр. 16.09: было :316, где утверждение несёт строка с `||`, непригодной для ячейки таблицы `if !any || v <= 0`). Воспроизведено исполнением 07.09 (выброшенная проба на копии дерева): `第零章:序幕` ингест режет главой, а чанкер заголовок НЕ снимает — `heading=""`, сырой CJK-маркер уезжает модели; `parseSectionNumeral` на `零`/`0`/`〇` даёт `0,false` (контроль: `一`=1, `十二`=12); номера расходятся (`第一章` = `Chapter 2` при «Глава 1»); 84-рунный заголовок: ингест `false`, чанкер `ok=true`. ⚠ **Испр. 07.09 — без этой оговорки строка читается как ЛОЖНАЯ:** расхождение живёт ТОЛЬКО у заголовка С СЕПАРАТОРОМ после юнита (`第四章:…`); без сепаратора оба предиката дают `false` на любой длине, потому что такую строку отвергают и `isHeaderSeparator` ингеста, и `matchHeaderLine` чанкера. Пере-снято оркестратором на копии `d6dfc49`: с сепаратором 59 и 60 рун — оба `true`; 61 и 84 — ингест `false` при чанкере `ok=true n=4`; без сепаратора 12/55/59/60/61/84 — `false`/`false` во всех шести. Граница ровно `chapterHeaderMaxRunes` = 60. Перекрёстного теста нет ни в одном из 97 тестов `internal/chunk`. **(а) $0 СЕЙЧАС — пин ИЗВЕСТНОГО расхождения, а не паритет:** красный тест в `main` не ложится (`Makefile:58` `battery: build vet fmt lint test`), скип — класс D39.208; поэтому тест утверждает, что на `第零章` и на 61–84-рунной строке ингест и чанкер СЕГОДНЯ расходятся, назван этой строкой и краснеет ровно тогда, когда приземлится фикс (б), заставляя фиксера его перевернуть. Дизайн-пак 161 §4.5 паритет-тест ОПИСЫВАЕТ, пишет его пак стройки — пин (а) этому не мешает. **(б) В ОКНО ПЕРЕНАРЕЗКИ:** сам фикс меняет ТЕКСТ чанка ⇒ бампает `chunkerVersion` ⇒ снапшот обеих волн (`render.go:55-58` — «a deliberate re-translation»); отдельным актом он платит ту самую перепокупку, которую отменяет. ⚠ Ось «обязательность юнита» — НЕ трогать: носитель строка **303** (⚠ испр. 07.09: research/33 приписывал её `D39.207`, в теле ноты этого нет — греп по предмету 0 при 23 строках тела) | бэкенд | скоро для (а); (б) — в окне перекроя (шаг 3) | (а) пин расхождения · (б) сведение двух предикатов к ингестовским стражам внутри пака перекроя | research/33 Д3, research/27 §6 | -| 350 | ⚠ **ИСПОЛНЕНО 07.09 (`D39.225`) КРОМЕ ОДНОГО: по каждой из шести функций назван исход — четыре получили причину жизни комментарием («NO CALLER TODAY: contract surface waiting on backlog row 12»), дубль инлайна свёрнут в `finalStageName()`. ОСТАЁТСЯ словарь родов в четырёх носителях; текст его собственной ошибки врать перестал.** **РЕФАКТОРИНГ ОБЛЕГЧЕНИЯ ВЕДЕНИЯ (санкция владельца 07.09) — снапшот-нейтрально, и заказ здесь «решить», а не «удалить».** Вызовов вне определения ноль у шести функций (греп 07.09; КОНТРОЛЬ — `SplitChunks` 34 живых вызова): `obs.SafeGo`, `text.TokenizeCyrillic`, `CheapGateResult.UnitScaleHard`/`UnitScaleSoft`, `Bank.Voices()`, `Bank.Pairs()`. ⚠ **Четыре из шести стоят НАМЕРЕННО, и слепое удаление снимет намеренное:** `UnitScaleHard/Soft` сами называют, кого ждут — `checks/cheapgates.go:155-156`=`Total() is unchanged` «for the report and a future hard gate», то есть строку **12**; `TokenizeCyrillic` — образец паттерна value-default, на который ссылаются `checks/sanitizer.go:21`=`value-default pattern, like text.TokenizeCyrillic` и `:197`; `SafeGo` — намеренный контраст к `obs/panic.go`, названный решением `backend/internal/pipeline/waverun.go:420`=`NOT obs.SafeGo` — ⚠ испр. 16.09: было :405 («NOT obs.SafeGo»), и его удаление повесит два комментария в воздухе — класс строки **299**; `Voices`/`Pairs` (`membank/memory.go:371-376`=`address-register journal (frozen for` «frozen for the job») ждут потребителя, которого держит строка **13б**. ⇒ по каждой ОДИН исход с объявлением в отчёте: удалить ЛИБО назвать причину жизни в комментарии. Плюс ИМЯ последней стадии дважды одинаковым инлайном — `r.Pipeline.Stages[n-1].Name` — ⚠ **испр. 16.09: ДУБЛЬ УСТРАНЁН, предмет закрыт кодом:** оба места берут теперь общий хелпер (`backend/internal/pipeline/export.go:281`=`lastStage := r.finalStageName()` и `quality.go:485` тем же вызовом; инлайна `Stages[n-1].Name` в обоих файлах ноль, `finalStageName` по движку 4 вхождения). Прежний адрес был `pipeline/export.go:283` и `quality.go:342` (адреса на `d6dfc49`). ⚠ **Испр. 07.09: и research/33 §7.1, и первая редакция этой строки называли здесь «готовый `finalStageWave()`» — это ДРУГАЯ функция**: она возвращает ВОЛНУ (`snapshot.go:247`, вызовов 13 — 10 прод и 3 теста), а хелпера для ИМЕНИ не существовало вовсе, и «при готовом хелпере» читалось как «работа уже сделана» и словарь родов в четырёх носителях (`membank/memory.go`, `membank/memseed.go`, `backend/internal/terminology/classify.go:40`=`Genders is the closed vocabulary` — ⚠ испр. 16.09: было :50, промт), где текст собственной ошибки врёт о принимаемом множестве. ⛔ Границы санкции: НЕ дробить `internal/pipeline` и НЕ переписывать `Runner` (`12-go-style-notes.md` §1, D39.23), ничего, что двигает снапшот / хеш запроса / ключ манифеста. ⚠ Адреса сняты research/33 на `e69902a`, а лендинг 07.09 тронул `memseed.go` и `export.go` — пере-снимать командой, не по тексту | бэкенд | когда-нибудь | попутный проход с батареей + объявление исхода по каждой функции | research/33 §7.1, санкция владельца 07.09 | +| 346 | ⚠ **ПОЛОВИНА (а) ЗАКРЫТА 07.09 (`D39.225`): пин расхождения и паритет-тест стоят, оба под мутациями. ОСТАЁТСЯ (б) — фикс в окне перенарезки.** ⛔ **ПРАВИЛО ЗАГОЛОВКА РАЗЪЕХАЛОСЬ ПО ТРЁМ ПРЕДИКАТАМ, И «第零章» ЛОМАЕТ ПРОЛОГ — две половины с РАЗНОЙ ценой.** Страж длины живёт только в ингесте (`backend/internal/chunk/ingest.go:341`=`const chapterHeaderMaxRunes = 60` `chapterHeaderMaxRunes = 60`, применён `backend/internal/chunk/ingest.go:357`=`> chapterHeaderMaxRunes`; в `chunker.go` `RuneCountInString` — 0 хитов), осмысленность номера — только в чанкере (`backend/internal/chunk/chunker.go:315-317`=`v := section + num` — ⚠ испр. 16.09: было :316, где утверждение несёт строка с `||`, непригодной для ячейки таблицы `if !any || v <= 0`). Воспроизведено исполнением 07.09 (выброшенная проба на копии дерева): `第零章:序幕` ингест режет главой, а чанкер заголовок НЕ снимает — `heading=""`, сырой CJK-маркер уезжает модели; `parseSectionNumeral` на `零`/`0`/`〇` даёт `0,false` (контроль: `一`=1, `十二`=12); номера расходятся (`第一章` = `Chapter 2` при «Глава 1»); 84-рунный заголовок: ингест `false`, чанкер `ok=true`. ⚠ **Испр. 07.09 — без этой оговорки строка читается как ЛОЖНАЯ:** расхождение живёт ТОЛЬКО у заголовка С СЕПАРАТОРОМ после юнита (`第四章:…`); без сепаратора оба предиката дают `false` на любой длине, потому что такую строку отвергают и `isHeaderSeparator` ингеста, и `matchHeaderLine` чанкера. Пере-снято оркестратором на копии `d6dfc49`: с сепаратором 59 и 60 рун — оба `true`; 61 и 84 — ингест `false` при чанкере `ok=true n=4`; без сепаратора 12/55/59/60/61/84 — `false`/`false` во всех шести. Граница ровно `chapterHeaderMaxRunes` = 60. Перекрёстного теста нет ни в одном из 97 тестов `internal/chunk`. **(а) $0 СЕЙЧАС — пин ИЗВЕСТНОГО расхождения, а не паритет:** красный тест в `main` не ложится (`Makefile:58` `battery: build vet fmt lint test`), скип — класс D39.208; поэтому тест утверждает, что на `第零章` и на 61–84-рунной строке ингест и чанкер СЕГОДНЯ расходятся, назван этой строкой и краснеет ровно тогда, когда приземлится фикс (б), заставляя фиксера его перевернуть. Дизайн-пак 161 §4.5 паритет-тест ОПИСЫВАЕТ, пишет его пак стройки — пин (а) этому не мешает. **(б) В ОКНО ПЕРЕНАРЕЗКИ:** сам фикс меняет ТЕКСТ чанка ⇒ бампает `chunkerVersion` ⇒ снапшот обеих волн (`render.go:55-58` — «a deliberate re-translation»); отдельным актом он платит ту самую перепокупку, которую отменяет. ⚠ Ось «обязательность юнита» — НЕ трогать: носитель строка **303** (⚠ испр. 07.09: research/33 приписывал её `D39.207`, в теле ноты этого нет — греп по предмету 0 при 23 строках тела) | бэкенд | скоро для (а); (б) — в окне перекроя (шаг 3) | (а) пин расхождения · (б) сведение двух предикатов к ингестовским стражам внутри пака перекроя | research/33 Д3, research/27 §6 | +| 350 | ⚠ **ИСПОЛНЕНО 07.09 (`D39.225`) КРОМЕ ОДНОГО: по каждой из шести функций назван исход — четыре получили причину жизни комментарием («NO CALLER TODAY: contract surface waiting on backlog row 12»), дубль инлайна свёрнут в `finalStageName()`. ОСТАЁТСЯ словарь родов в четырёх носителях; текст его собственной ошибки врать перестал.** **РЕФАКТОРИНГ ОБЛЕГЧЕНИЯ ВЕДЕНИЯ (санкция владельца 07.09) — снапшот-нейтрально, и заказ здесь «решить», а не «удалить».** Вызовов вне определения ноль у шести функций (греп 07.09; КОНТРОЛЬ — `SplitChunks` 34 живых вызова): `obs.SafeGo`, `text.TokenizeCyrillic`, `CheapGateResult.UnitScaleHard`/`UnitScaleSoft`, `Bank.Voices()`, `Bank.Pairs()`. ⚠ **Четыре из шести стоят НАМЕРЕННО, и слепое удаление снимет намеренное:** `UnitScaleHard/Soft` сами называют, кого ждут — `checks/cheapgates.go:155-156`=`Total() is unchanged` «for the report and a future hard gate», то есть строку **12**; `TokenizeCyrillic` — образец паттерна value-default, на который ссылаются `backend/internal/checks/sanitizer.go:21`=`value-default pattern, like text.TokenizeCyrillic` и `:197`; `SafeGo` — намеренный контраст к `obs/panic.go`, названный решением `backend/internal/pipeline/waverun.go:420`=`NOT obs.SafeGo` — ⚠ испр. 16.09: было :405 («NOT obs.SafeGo»), и его удаление повесит два комментария в воздухе — класс строки **299**; `Voices`/`Pairs` (`membank/memory.go:371-376`=`address-register journal (frozen for` «frozen for the job») ждут потребителя, которого держит строка **13б**. ⇒ по каждой ОДИН исход с объявлением в отчёте: удалить ЛИБО назвать причину жизни в комментарии. Плюс ИМЯ последней стадии дважды одинаковым инлайном — `r.Pipeline.Stages[n-1].Name` — ⚠ **испр. 16.09: ДУБЛЬ УСТРАНЁН, предмет закрыт кодом:** оба места берут теперь общий хелпер (`backend/internal/pipeline/export.go:281`=`lastStage := r.finalStageName()` и `quality.go:485` тем же вызовом; инлайна `Stages[n-1].Name` в обоих файлах ноль, `finalStageName` по движку 4 вхождения). Прежний адрес был `pipeline/export.go:283` и `quality.go:342` (адреса на `d6dfc49`). ⚠ **Испр. 07.09: и research/33 §7.1, и первая редакция этой строки называли здесь «готовый `finalStageWave()`» — это ДРУГАЯ функция**: она возвращает ВОЛНУ (`snapshot.go:247`, вызовов 13 — 10 прод и 3 теста), а хелпера для ИМЕНИ не существовало вовсе, и «при готовом хелпере» читалось как «работа уже сделана» и словарь родов в четырёх носителях (`membank/memory.go`, `membank/memseed.go`, `backend/internal/terminology/classify.go:40`=`Genders is the closed vocabulary` — ⚠ испр. 16.09: было :50, промт), где текст собственной ошибки врёт о принимаемом множестве. ⛔ Границы санкции: НЕ дробить `internal/pipeline` и НЕ переписывать `Runner` (`12-go-style-notes.md` §1, D39.23), ничего, что двигает снапшот / хеш запроса / ключ манифеста. ⚠ Адреса сняты research/33 на `e69902a`, а лендинг 07.09 тронул `memseed.go` и `export.go` — пере-снимать командой, не по тексту | бэкенд | когда-нибудь | попутный проход с батареей + объявление исхода по каждой функции | research/33 §7.1, санкция владельца 07.09 | | 351 | **ЛИНТ СЛОВАРЯ КЛАССИФИКАТОРА ПИНИТ ОДНО НАПРАВЛЕНИЕ: слово, УБРАННОЕ из Go, не ловит ничто.** Гейт `TestEveryClassifierPromptSpeaksTheEnginesVocabulary` (лендинг `D39.225`) утверждает «каждое слово из `terminology.Types`/`Genders` названо в промте пары» — и потому сжимается вместе со своим предметом: выкинутый класс `title` оставляет батарею зелёной (замер 07.09 на копии: 19 ok / 0 FAIL). Вырожденный предел закрыт стражем `len(classifierVocabulary()) == 0`, общий случай — нет. Настоящий дом — пин САМОГО словаря, которого в репозитории нет (research/33 Д1: 0 тестов на `terminology.Types`). ⚠ Граница названа зоной самостоятельно, в заказ пака не входила | бэкенд | когда-нибудь | пин словаря (голден или рефлексивный тест) | `D39.225`, research/33 Д1 | -| 352 | **ПЯТЬ РУКОПИСНЫХ СПИСКОВ АРМ-КОНФИГОВ ЖИВУТ РЯДОМ С ДВУМЯ ГЕЙТАМИ, КОТОРЫЕ ТЕПЕРЬ ГЛОБЯТ.** `pipeline/promptlabel_test.go:45`=`pipeline-arm-glm.yaml` · `config/echoregen_shipping_test.go:35`=`pipeline-arm-glm.yaml` · `config/content_labels_test.go:529`=`pipeline-c1.yaml` и `:575` · `config/prompt_pack_test.go:239`=`pipeline-arm-mistral.yaml` перечисляют армы поимённо; новый арм автоматически попадает в `TestAnArmIsTheProductionConfigWithADifferentEditor` и `TestSwapArmConfigs` и проходит мимо всех пяти. Найдено приёмкой `D39.225`, вне заказа пака; предсуществующее | бэкенд | когда-нибудь (со следующим касанием армов) | свести пять списков к глобу | `D39.225` | +| 352 | **ПЯТЬ РУКОПИСНЫХ СПИСКОВ АРМ-КОНФИГОВ ЖИВУТ РЯДОМ С ДВУМЯ ГЕЙТАМИ, КОТОРЫЕ ТЕПЕРЬ ГЛОБЯТ.** `backend/internal/pipeline/promptlabel_test.go:45`=`pipeline-arm-glm.yaml` · `backend/internal/config/echoregen_shipping_test.go:35`=`pipeline-arm-glm.yaml` · `backend/internal/config/content_labels_test.go:529`=`pipeline-c1.yaml` и `:575` · `backend/internal/config/prompt_pack_test.go:240`=`pipeline-arm-mistral.yaml` перечисляют армы поимённо; новый арм автоматически попадает в `TestAnArmIsTheProductionConfigWithADifferentEditor` и `TestSwapArmConfigs` и проходит мимо всех пяти. Найдено приёмкой `D39.225`, вне заказа пака; предсуществующее | бэкенд | когда-нибудь (со следующим касанием армов) | свести пять списков к глобу | `D39.225` | | 353 | **КОНТРАКТ СЕКЦИИ ПРЕДЛОЖЕНИЙ В САЙДКАРЕ БАНКА ЗАПИНЕН ПО ПОЛЯМ И ПОРЯДКУ, НО НЕ ИСЧЕРПЫВАЮЩЕ — строка заведена ПРАВИЛОМ ОСТАНОВКИ, а не находкой.** Три круга приёмки `D39.225` находили в одной новой секции всё более узкие дыры: сперва семь полей без утверждений, потом `Freq` и своп списков, потом ранжирование и класс пустого `Dst`. Каждая была настоящей и предъявлена посадкой; каждый следующий круг стоил больше и покупал меньше. Сегодня запинены: все решающие поля против стоп-строки · порядок против стоп-СТРОК на двух уровнях · рефлективный страж «ни одно поле проекции не нулевое» (ловит поле, добавленное завтра и не заполненное). ⚠ **Дописка 08.09 (приёмка `D39.226`):** у поля `SettledByBank` стоп-строки нет свидетеля в списке «полей, которых сайдкар намеренно НЕ несёт» (`bankexport_test.go`) — то есть его сознательное отсутствие в проекции не утверждено ничем; закрывать вместе с первым читателем секции. ⚠ Границу называет сам гейт: поле, которое отрастил `BankStopRow` и которое СЛЕДОВАЛО бы проецировать, механически не ловится — это суждение того, кто поле добавляет. ⇒ вернуться к исчерпывающему контракту, когда у секции появится ЧИТАТЕЛЬ (платформенная половина строки **224**): пока читателя нет, расхождение ничем не судится, а в день его появления разница станет семантикой задним числом — второй ярус класса A `18-bank-ontology.md` | бэкенд + платформа | когда-нибудь (гейт: появление читателя секции, строка 224) | исчерпывающий пин контракта секции вместе с её первым потребителем | `D39.225` п.10 | | 354 | ⛔ **ОПЛАЧЕННЫЙ `2xx` С ОБОРВАННЫМ ТЕЛОМ — КЛАСС, СТОИВШИЙ 32 % ЖИВОГО ПРОГОНА, И СТРАНИЦА КВИРКОВ О НЁМ МОЛЧИТ.** Живой прогон 08.09 (10 глав, `committed=$1.259217`): два вызова редактора вернулись `2xx` с нечитаемым JSON и были ОПЛАЧЕНЫ — `$0.407606`, то есть **32 % бюджета прогона**. Движок класс ЗНАЕТ и обрабатывает штатно: `backend/internal/pipeline/disposition.go:80`=`FlagDecodeError FlagReason` `FlagDecodeError` — «2xx with an unreadable body — billed, conservatively settled, flagged». ⛔ Но `docs/experiments/00-provider-quirks.md` — страница, которую канон велит читать ПЕРЕД правкой адаптеров и вызовов, — о нём не несёт НИ СТРОКИ: греп по `decode`/`unexpected end of JSON`/«оборван» даёт **0 при 250 строках файла** (контроль: слово `provider` там встречается 3 раза, то есть спрошено существующее). ⇒ следующая сессия, читающая квирки перед платным прогоном, не узнает о поведении, которое съедает треть бюджета. ⛔ **испр. 08.09: МЕХАНИЗМ НАЗВАН ЗДЕСЬ НЕВЕРНО — это не свойство провайдера, а дефект движка, и носитель у него теперь строка 360.** Полигон замером exp-23 п.5 показал, что за подписью «нечитаемое тело» стоит ТАЙМАУТ ЧТЕНИЯ по `attempt_s`, который движок сам же выбрасывает в `_`. ⇒ эта строка остаётся ТОЛЬКО про пробел страницы квирков: она обязана предупреждать, ЧТО оператор увидит и почему, со ссылкой на 360, а не приписывать поведение вендору. ⚠ Зона — ПОЛИГОН (`docs/experiments/` по зонной таблице), живой сессии полигона нет; строка заведена оркестратором как носитель, писать в файл полигону | полигон | скоро (перед следующим платным прогоном любой зоны) | строка в `00-provider-quirks.md` с частотой, стоимостью и тем, что движок делает с классом | живой прогон 08.09, пак «правда оператору и деньги» | | 356 | **КНИГА У СВОЕГО ПОЖИЗНЕННОГО ПОТОЛКА РОЛИ НАВСЕГДА ОСТАЁТСЯ БЕЗ КОНСОЛИДИРОВАННОГО БАНКА, и ни одно сообщение не говорит именно этого.** `store/ledger.go` `RoleSpentUSD` суммирует чекпойнты роли за ВСЮ жизнь книги, предполётный срез сеет `probe := spent` и обрывается на `probe+want > budgetUSD`; при `fits == 0` цикл попыток не запускается вовсе. ⚠ Оператор ПРИ ЭТОМ извещён — `terminologist.go:936` печатает `batches_planned=N batches_running=0 batches_dropped=N spent_usd budget_usd` ДО первого вызова (сверено оркестратором 08.09), поэтому «тихо» здесь неверно, и находка приёмки в этой части ОТКЛОНЕНА доводом зоны. Верен остаток: сообщение говорит про ЭТОТ прогон, а не про то, что книга исчерпала пожизненный бюджет роли и консолидации не получит НИКОГДА, сколько её ни перезапускай. Свойство `budget_usd`, а не фильтра пака «правда оператору и деньги»: тот на решение бюджета не влияет. ⇒ решить, что показывать оператору и владельцу: отдельное сообщение «книга у пожизненного потолка роли», подъём потолка как явный акт, или сознательное молчание с записью | бэкенд | когда-нибудь (гейт: первая книга, упёршаяся в пожизненный потолок роли) | сообщение об исчерпании пожизненного бюджета либо ратифицированное молчание | приёмка `D39.226`, линза «вне карты» | @@ -317,11 +317,11 @@ | 403 | **ЦЕПОЧКА «СВИП → ОСТАНОВКА → НАСТОЯЩИЙ systemd» НЕ ПРОЙДЕНА НИЧЕМ, и это объявлено ЗАРАНЕЕ, а не найдено потом.** Платформенная сессия дважды за смену упиралась в одно: пины говорят о ЮНИТЕ (живой systemd-стенд у зоны есть) либо о СТОРЕ (живой Postgres есть), а утверждения о поведении живут в СВИПЕ — и стенда, который проводит служебный обход через настоящую остановку настоящего юнита, в зоне нет. ⇒ две правки этой смены (`--no-block` в `560ca20` и ответ живым именем юнита в `00d590e`) доказаны каждая на своём уровне и НЕ доказаны сквозной цепочкой; так и записано в обеих секциях «что не удалось». ⚠ Заведено строкой по её же просьбе — чтобы следующий не открывал вопрос заново и не принял «пин зелёный» за «цепочка проверена». ⭐ Отдельно ценно, что предупреждение сделано ДО сдачи, а не после: сессия назвала границу своего доказательства сама | платформа | когда-нибудь | есть стенд, проводящий свип через настоящую остановку настоящего юнита, ИЛИ записано решение, что такой стенд не строится и почему | объявленная граница платформенной сессии, 11.09 | | 404 | ⚠ **СТРОКА ПЕРЕ-ПИСАНА 11.09: её центральное утверждение было МОЕЙ ОШИБКОЙ.** Первая редакция говорила, что мутация с уехавшим якорем «не краснеет, перестаёт сажаться, и в отчёте „не посадилась“ неотличимо от „пережила“», и что механизма против этого НЕТ. **Механизм есть, и он в самом `tmmutate`:** запись с уехавшим якорем получает вердикт `rotted`, печатается отдельной строкой и **засчитывается как неожиданный исход — прогон завершается ненулевым кодом**; довод записан в самом инструменте (`backend/cmd/tmmutate/main.go`, греп `an entry whose anchor moved guards nothing`). Пере-снято мной по возражению движковой сессии, которая в этот класс наступила и была поймана СВОИМ ЖЕ прибором: `make mutations` дал `MAKE-EXIT=2 · RED 151 · SURVIVED 0 · ROTTED 1`, и протухшей оказалась ЧУЖАЯ запись, сломанная её правкой. ⛔ **ЖИВОЙ ОСТАТОК КЛАССА — не мутации, а ДОКИ И КАТАЛОГИ, где такого счётчика нет.** Линтер доков сверяет ПО СОДЕРЖИМОМУ только якоря опт-ин токен-формы; голый `файл:строка` он не видит по построению, и его протухание не даёт ни красноты, ни строки в выводе (замер 10.09: из 19 голых якорей живых секций реестра долга съехали 10, при 9 из 9 целых токен-формных). ⭐ И побочный урок, названный сессией: знаменатель проверки якорей надо брать ИЗ КАТАЛОГА, а не из своих правок — она проверила три свои записи и не проверила чужую, которую сломала | доки | скоро | у голых `файл:строка` в живых доках есть счётчик, дающий ненулевой выход, — либо они переведены в токен-форму | находка движковой сессии 11.09, пере-снята оркестратором | | 405 | **РАЗМЕН ПО СТРОКЕ 375 ИМЕЕТ НАЗВАННУЮ ЦЕНУ: проекция расходится с леджером на оборванной попытке.** Починка «обрыв не стирает уже заработанный вердикт» (заландена `3084766`) оставляет позиции прежний `cost_usd`, поэтому деньги ОБОРВАННОЙ попытки в попозиционную проекцию не добавляются: **леджер полон, проекция нет**. Названо самой движковой сессией при сдаче, а не найдено потом. ⇒ тот, кто будет сверять проекцию с леджером на книге, где были обрывы поверх отгруженных позиций, увидит расхождение и не должен принять его за потерю денег — деньги в леджере. ⚠ Заведено ОТДЕЛЬНОЙ строкой намеренно: это цена размена, который оркестратор утвердил осознанно (потеря отгруженного текста хуже неточности отчёта), и она обязана стоять рядом с ним, а не всплыть через месяц | бэкенд | когда-нибудь | попозиционная проекция и леджер сходятся на книге с обрывами поверх отгруженных позиций, либо расхождение объявлено в самой проекции | сдача движковой сессии 11.09 | -| 406 | ⛔ **КОНСИСТЕНТНОСТЬ КНИГИ НИКТО НЕ СПРАШИВАЕТ — ПРИБОРА ПО ОТГРУЖЕННОМУ ТЕКСТУ НЕТ ВОВСЕ.** Мера «сколько РАЗНЫХ передач дал один термин» ПОСТРОЕНА (`Spread`/`Variants`, `backend/internal/pipeline/mining.go:384-384`=`how many DISTINCT renderings the drafts produced`), но считается по ЧЕРНОВИКУ, на стопе майнинга, ДО редакторской волны, и читает её только человеческая таблица подписи. По ФИНАЛЬНОМУ тексту такой меры не существует ни одной. ⇒ приоритет №1 владельца («консистентные термины на всю книгу») сегодня НЕПРОВЕРЯЕМ в принципе: все четыре A/B, показавшие пользу банка, меряли ПРИСУТСТВИЕ инъектированной формы в чанке, а не отсутствие конкурирующей. **Лечение $0 и переиспользует готовое:** тот же счёт по отгружаемому тексту + строка отчёта сборки «термин X отдан тремя формами в главах 12, 340, 901». Предмет не пуст: полигонный прибор на стенде дал 13–16 % терминов с более чем одной передачей. ⚠ Это ЕДИНСТВЕННАЯ работа, которая делает качество ПРЕДЪЯВИМЫМ; без неё кривую деградации по главам снять не с чего ⛔ **ИСПОЛНЕНО ЧАСТЬЮ 11.09 ПРОГОНОМ A, и первый же результат снял мою же формулировку слепого пятна.** Прибор построен полигоном и дал по отгруженному тексту «0 терминов из 40 отданы более чем одной формой». ⚠ **Ноль держался на том, что прибор НЕ СМОТРЕЛ:** кандидаты искались регуляркой, требующей ЗАГЛАВНОЙ буквы (`[А-ЯЁ][а-яёА-ЯЁ-]+`), и склонённые строчные формы («гу-мастера», «наложницей») отпадали ДО правила сравнения. Я заказал переписать правило сравнения пословно — **заказ бил мимо**: критик применил этот рецепт к прибору на боевых данных, и не вернулся НИ ОДИН из 29 потерянных термов. Починка ГЕНЕРАЦИИ кандидатов на тех же данных даёт **48 найденных термов вместо 40** — это замер, и он стоит. ⛔ **А «шесть строк со `spread ≥ 2`» ИСПР. 11.09 — я процитировал число КРИТИКА, которое полигон ОТОЗВАЛ в том самом отчёте, что я принял актом.** Её собственный пере-замер той же починки даёт **девять**, и все девять — ШУМ: оконный поиск глотает соседние слова и считает каждое окно отдельной формой («старейшины и», «Фан не», «глава рода он»). Её формулировка дословно: «покрытие 40 → 48 — замер; счёт расхождений у починенного прибора — шум», улика — `checks/spread-candidate-fix-probe.txt`, и окну недостаёт фильтра, отвергающего лишние слова. ⇒ **числа расхождений у починенного прибора НЕТ вовсе**, и заказ следующему — сначала фильтр окна, потом счёт. ⭐ Класс моей ошибки: я взял число из отчёта, не дочитав до раздела, где его автор от него отказался. ⚠ И заголовочный «0» неустойчив к порогу складывания: под пословным правилом `沈翠` распадается на «Шэнь»/«Шэнь Цуй» и число становится 1. ⇒ остаток ряда: прибор по ФИНАЛЬНОМУ тексту с (а) генерацией кандидатов без регистрового фильтра, (б) названным порогом складывания, (в) замеренной чувствительностью к нему. ⭐ **ПРАВИЛО ВЫБОРА ПЕРВИЧНОЙ КОЛОНКИ — ратифицируется актом приёмки пака 11.09; записано здесь, чтобы пережило смену, и УЖЕ ИСПРАВЛЕНО ДВАЖДЫ.** У прибора две колонки: СТРОГАЯ (равенство стеммов, как у пост-проверки) и ЯКОРНАЯ (признаёт склонённую передачу). **Первичная — ЯКОРНАЯ, строгая идёт полом точности рядом.** ⛔ **Направления ошибок, иначе довод читается наоборот:** строгая ошибается в сторону ЛОЖНОЙ ТРЕВОГИ (форма доехала склонённой, а она объявляет нарушение); якорная — в сторону СОКРЫТИЯ (засчитывает совпадение, которого по смыслу нет). **Как детекторы нарушения на прогоне A:** строгая дала 18 сообщений, настоящих 7 ⇒ точность **0.39**; якорная дала **9** при 7 настоящих ⇒ **0.78**. ⚠ **Число ИСПР. 11.09 и было 1.00 ДО ужесточения `NearStems` до строгого префикса** — ужесточение вернуло `邪魔` («злой»/«злог» — замена, не усечение) в ложные, и это цена размена, которым закрыты три коллизии многословных передач. Вторая ложная — `话事人`, однословная передача, якорить нечем. ⇒ **каждое пятое сообщение первичной колонки ложное, и читать её надо с этой поправкой.** ⇒ основание НЕ «ложная тревога дешевле сокрытия» (так было написано, и так оно аргументирует ОБРАТНОЕ), а такое: **детектор, врущий в 61 % сообщений, не громче — его перестают читать, а непрочитанный прибор не защищает ничего.** ⛔ **Второе основание, от данных не зависящее:** писатели `decl.forms` в не-тестовом Go только сидовые (`internal/seed/normalize.go:85`=`d := Decl{Invariant: t.Decl.Invariant`, `internal/membank/memseed.go:166`=`b, mErr := json.Marshal(declInfo{`), майнер форм не пишет, а дверь `BankCorrection` контракта поля `decl`/`forms` не несёт вовсе ⇒ на дорожке продукта форм нет НИ У КОГО, и строгая колонка там вырождается в одношаговое равенство. ⚠ Иллюстрация «0 форм из 69 в банках прогона» основанием НЕ является. ⛔ **ДВА ЧИСЛА ТОЧНОСТИ, путать нельзя (замерено зоной 11.09): само ОТНОШЕНИЕ строгого префикса — 17 из 30 равномерной выборки принятых пар, ≈0.57** (`рода~родной`, `гор~горная`, `так~также` — разные леммы); **колонка в своих ограждениях — 11 из 11 на прогоне A.** ⇒ работает не отношение, а ограждения (якорь · многословное окно · границы предложения), и их эффективность замерена на ОДНОЙ книге. Названный отказ: где слово банковской передачи окажется соседом другого слова в той же позиции окна, колонка соврёт в сторону сокрытия. ⛔⛔ **ПРАВИЛО ДЕЙСТВУЕТ ПРИ УСЛОВИИ: пока прибор ФЛАГУЕТ и не отказывает.** Станет он гейтом отгрузки — ложная тревога начнёт стоить удержанного текста или пере-генерации, то есть ДЕНЕГ, асимметрия перевернётся, и порядок колонок надо решать заново. ⇒ **триггеров пере-открытия ДВА:** (1) появился МАШИННЫЙ писатель `decl.forms`; (2) **эта колонка стала гейтом** — носители: `Gates.Glossary.PostcheckGate` построен (`backend/internal/pipeline/quality.go:361`=`gateOn := r.Pipeline.Gates.Glossary.PostcheckGate`, свёрнут в снапшот) и выставлен в НУЛЕ из четырёх живых конфигов, плюс ряд **296** (точечная перегенерация по промаху — направление владельца, работы нет). ⚠ Второй триггер сегодня БЛИЖЕ первого. ⚠ Прежнее моё решение (первичная — строгая) принято и отменено 11.09 в один день; цена разворота — согласие с ручным оракулом 13/16 против 10/16, **и это n=16: направление, а не величина.** Так же и 0.57 — порядок, а не третья цифра.| бэкенд | **скоро** | счёт расхождения форм по отгруженному тексту + строка отчёта сборки | аудит банка 11.09, `research/34` §2.1 | +| 406 | ⛔ **КОНСИСТЕНТНОСТЬ КНИГИ НИКТО НЕ СПРАШИВАЕТ — ПРИБОРА ПО ОТГРУЖЕННОМУ ТЕКСТУ НЕТ ВОВСЕ.** Мера «сколько РАЗНЫХ передач дал один термин» ПОСТРОЕНА (`Spread`/`Variants`, `backend/internal/pipeline/mining.go:384-384`=`how many DISTINCT renderings the drafts produced`), но считается по ЧЕРНОВИКУ, на стопе майнинга, ДО редакторской волны, и читает её только человеческая таблица подписи. По ФИНАЛЬНОМУ тексту такой меры не существует ни одной. ⇒ приоритет №1 владельца («консистентные термины на всю книгу») сегодня НЕПРОВЕРЯЕМ в принципе: все четыре A/B, показавшие пользу банка, меряли ПРИСУТСТВИЕ инъектированной формы в чанке, а не отсутствие конкурирующей. **Лечение $0 и переиспользует готовое:** тот же счёт по отгружаемому тексту + строка отчёта сборки «термин X отдан тремя формами в главах 12, 340, 901». Предмет не пуст: полигонный прибор на стенде дал 13–16 % терминов с более чем одной передачей. ⚠ Это ЕДИНСТВЕННАЯ работа, которая делает качество ПРЕДЪЯВИМЫМ; без неё кривую деградации по главам снять не с чего ⛔ **ИСПОЛНЕНО ЧАСТЬЮ 11.09 ПРОГОНОМ A, и первый же результат снял мою же формулировку слепого пятна.** Прибор построен полигоном и дал по отгруженному тексту «0 терминов из 40 отданы более чем одной формой». ⚠ **Ноль держался на том, что прибор НЕ СМОТРЕЛ:** кандидаты искались регуляркой, требующей ЗАГЛАВНОЙ буквы (`[А-ЯЁ][а-яёА-ЯЁ-]+`), и склонённые строчные формы («гу-мастера», «наложницей») отпадали ДО правила сравнения. Я заказал переписать правило сравнения пословно — **заказ бил мимо**: критик применил этот рецепт к прибору на боевых данных, и не вернулся НИ ОДИН из 29 потерянных термов. Починка ГЕНЕРАЦИИ кандидатов на тех же данных даёт **48 найденных термов вместо 40** — это замер, и он стоит. ⛔ **А «шесть строк со `spread ≥ 2`» ИСПР. 11.09 — я процитировал число КРИТИКА, которое полигон ОТОЗВАЛ в том самом отчёте, что я принял актом.** Её собственный пере-замер той же починки даёт **девять**, и все девять — ШУМ: оконный поиск глотает соседние слова и считает каждое окно отдельной формой («старейшины и», «Фан не», «глава рода он»). Её формулировка дословно: «покрытие 40 → 48 — замер; счёт расхождений у починенного прибора — шум», улика — `checks/spread-candidate-fix-probe.txt`, и окну недостаёт фильтра, отвергающего лишние слова. ⇒ **числа расхождений у починенного прибора НЕТ вовсе**, и заказ следующему — сначала фильтр окна, потом счёт. ⭐ Класс моей ошибки: я взял число из отчёта, не дочитав до раздела, где его автор от него отказался. ⚠ И заголовочный «0» неустойчив к порогу складывания: под пословным правилом `沈翠` распадается на «Шэнь»/«Шэнь Цуй» и число становится 1. ⇒ остаток ряда: прибор по ФИНАЛЬНОМУ тексту с (а) генерацией кандидатов без регистрового фильтра, (б) названным порогом складывания, (в) замеренной чувствительностью к нему. ⭐ **ПРАВИЛО ВЫБОРА ПЕРВИЧНОЙ КОЛОНКИ — ратифицируется актом приёмки пака 11.09; записано здесь, чтобы пережило смену, и УЖЕ ИСПРАВЛЕНО ДВАЖДЫ.** У прибора две колонки: СТРОГАЯ (равенство стеммов, как у пост-проверки) и ЯКОРНАЯ (признаёт склонённую передачу). **Первичная — ЯКОРНАЯ, строгая идёт полом точности рядом.** ⛔ **Направления ошибок, иначе довод читается наоборот:** строгая ошибается в сторону ЛОЖНОЙ ТРЕВОГИ (форма доехала склонённой, а она объявляет нарушение); якорная — в сторону СОКРЫТИЯ (засчитывает совпадение, которого по смыслу нет). **Как детекторы нарушения на прогоне A:** строгая дала 18 сообщений, настоящих 7 ⇒ точность **0.39**; якорная дала **9** при 7 настоящих ⇒ **0.78**. ⚠ **Число ИСПР. 11.09 и было 1.00 ДО ужесточения `NearStems` до строгого префикса** — ужесточение вернуло `邪魔` («злой»/«злог» — замена, не усечение) в ложные, и это цена размена, которым закрыты три коллизии многословных передач. Вторая ложная — `话事人`, однословная передача, якорить нечем. ⇒ **каждое пятое сообщение первичной колонки ложное, и читать её надо с этой поправкой.** ⇒ основание НЕ «ложная тревога дешевле сокрытия» (так было написано, и так оно аргументирует ОБРАТНОЕ), а такое: **детектор, врущий в 61 % сообщений, не громче — его перестают читать, а непрочитанный прибор не защищает ничего.** ⛔ **Второе основание, от данных не зависящее:** писатели `decl.forms` в не-тестовом Go только сидовые (`backend/internal/seed/normalize.go:85`=`d := Decl{Invariant: t.Decl.Invariant`, `backend/internal/membank/memseed.go:166`=`b, mErr := json.Marshal(declInfo{`), майнер форм не пишет, а дверь `BankCorrection` контракта поля `decl`/`forms` не несёт вовсе ⇒ на дорожке продукта форм нет НИ У КОГО, и строгая колонка там вырождается в одношаговое равенство. ⚠ Иллюстрация «0 форм из 69 в банках прогона» основанием НЕ является. ⛔ **ДВА ЧИСЛА ТОЧНОСТИ, путать нельзя (замерено зоной 11.09): само ОТНОШЕНИЕ строгого префикса — 17 из 30 равномерной выборки принятых пар, ≈0.57** (`рода~родной`, `гор~горная`, `так~также` — разные леммы); **колонка в своих ограждениях — 11 из 11 на прогоне A.** ⇒ работает не отношение, а ограждения (якорь · многословное окно · границы предложения), и их эффективность замерена на ОДНОЙ книге. Названный отказ: где слово банковской передачи окажется соседом другого слова в той же позиции окна, колонка соврёт в сторону сокрытия. ⛔⛔ **ПРАВИЛО ДЕЙСТВУЕТ ПРИ УСЛОВИИ: пока прибор ФЛАГУЕТ и не отказывает.** Станет он гейтом отгрузки — ложная тревога начнёт стоить удержанного текста или пере-генерации, то есть ДЕНЕГ, асимметрия перевернётся, и порядок колонок надо решать заново. ⇒ **триггеров пере-открытия ДВА:** (1) появился МАШИННЫЙ писатель `decl.forms`; (2) **эта колонка стала гейтом** — носители: `Gates.Glossary.PostcheckGate` построен (`backend/internal/pipeline/quality.go:361`=`gateOn := r.Pipeline.Gates.Glossary.PostcheckGate`, свёрнут в снапшот) и выставлен в НУЛЕ из четырёх живых конфигов, плюс ряд **296** (точечная перегенерация по промаху — направление владельца, работы нет). ⚠ Второй триггер сегодня БЛИЖЕ первого. ⚠ Прежнее моё решение (первичная — строгая) принято и отменено 11.09 в один день; цена разворота — согласие с ручным оракулом 13/16 против 10/16, **и это n=16: направление, а не величина.** Так же и 0.57 — порядок, а не третья цифра.| бэкенд | **скоро** | счёт расхождения форм по отгруженному тексту + строка отчёта сборки | аудит банка 11.09, `research/34` §2.1 | | 407 | **ПОСТ-ПРОВЕРКА БАНКА СПРАШИВАЕТ НЕ ТО: присутствие формы ГДЕ-НИБУДЬ в чанке вместо формы НА МЕСТЕ срабатывания, и про конкурирующую передачу не спрашивает никогда.** `backend/internal/membank/mempostcheck.go` — вопрос bag-of-words по всему чанку ⇒ дрейф ВНУТРИ составного имени невидим по построению. Замерено исполнением на копии: ряд `方源`→«Фан Юань» с алиасом `古月方源`, выход «Гу Юэ Фан Юань» даёт 0 промахов при подписанном каноне `古月 → Гуюэ`; контроль рядом (форма реально отсутствует) даёт 1 промах, то есть прибор спрошен и отвечает. ⚠ **У экземпляра ДВА корня, и смена вопроса закрывает только один:** ряд `古月` съеден равнотрастовым длиннейшим матчем (`memory.go` `suppressContained`) МОЛЧА. Дешёвая половина — проверять алиас-ключ на СОБСТВЕННУЮ канонную форму (день); дорогая (детектор значения по исходнику) — ряд **286**, загейчен замером. ⚠ Класс объявлен в дереве с 06.09 (`experiments/23-editor-tier.md` §Д50.3) — новизна нулевая, ряд заводится как НОСИТЕЛЬ, которого у него не было ⛔ **ИСПР. 11.09 ПО СЛОВУ ВЛАДЕЛЬЦА — РЯД БЫЛ НАПИСАН ПО НЕСУЩЕСТВУЮЩЕЙ ОСИ.** Слово: «нет такого понятия [подписанный термин], подписан либо ВЕСЬ банк, либо он в неконсистентном состоянии; есть вариант поставить галочку скипать подпись с фронта — тогда автоподписывание». Это ратифицировано `D39.144`: подписывается банк ЦЕЛИКОМ, пер-термная подпись прямо названа НЕ моделью продукта, дефолт движка — авто-продолжение с неподписанным банком, строки едут С ПОМЕТКОЙ. ⇒ **настоящий дефект глубже, чем «прибор не видит дрейфа»: в коде живёт пер-термный автомат из трёх состояний (`auto`, `draft`, `approved`) (`backend/internal/store/migrate.go:192`=`term status machine`), и пост-проверка считает нарушением ТОЛЬКО `approved` — то есть принимает решение по ЕДИНИЦЕ, КОТОРОЙ В ПРОДУКТОВОЙ МОДЕЛИ НЕТ.** Это и есть причина нуля при 18 найденных (строка **419**): сломана не поверхность, а ОСЬ решения. Закон `D39.104` на проводе один для всех строк; состояние книги — «подписана целиком» либо «авто-продолжение», и мерить надо им. | бэкенд | скоро | вопрос пост-проверки + видимость подавления вложенного ряда | аудит банка 11.09, находка `K3` (единственная пережившая верификацию) | -| 408 | **ДАННЫЕ БАНКА НЕ ДОСЕЯНЫ, И ИМЕННО ИЗ-ЗА ЭТОГО ГЕЙТ КОНСИСТЕНТНОСТИ НЕЛЬЗЯ ВКЛЮЧИТЬ.** ⛔ **ЧИСЛО ИСПР. 11.09 — ПРЕЖНЕЕ БЫЛО ДО-СТЕММЕРНОЙ БАЗОЙ, а ряд гейтил им решение владельца.** Пере-снято мною прогоном пинов размеченного корпуса (`TM_CHECKER_LABELS=1 go test ./internal/membank/ -run TestK6 -v`): **база (`metrics.json`, до стеммера и до #10) — tp=1 fp=14 ⇒ 0.0667**, и это то, что здесь стояло; **ОТГРУЗОЧНЫЙ путь СЕГОДНЯ — tp=1 fp=6 tn=251 ⇒ 0.1429**; со стеммизацией `decl`-форм — **fp=0 ⇒ 1.0000**. ⚠ И концентрация названа неверно: класса `转` на отгрузочном пути НЕТ ВОВСЕ (его снял стеммер), остаточные шесть — это `元石` ×2 и `蛊虫` ×4, то есть **ровно склонительный разрыв, лечащийся досевом форм**. ⇒ направление ряда верно, величина отставала на два улучшения, а список ложных описывал уже не тот прибор. ⭐ **И это прямо смыкает ряд с 423:** стеммизация `decl`-форм уводит точность в 1.0000, а `decl`-форм нет ни в одной машинной выгрузке — то есть «досеять данные» и есть лечение, но на дорожке продукта досевать некому. Три дыры, все в ДАННЫХ, не в Go: (а) глагольные и многословные термины засеяны с пустыми формами — один `炼化` дал 7 ложных промахов (⚠ **испр. 11.09: это число из ДРУГОГО замера** — `docs/experiments/23-editor-tier.md:7630`=`Все семь «промахов»`, не из `labels/metrics.json`; в размеченном корпусе `炼化` нет вовсе, и обе величины верны порознь, но ссылка была одна на две); (б) односимвольный ханьский ключ структурно вне автомата без `allow_short` (порог 2 знака, `membank/memory.go:72`=`minKeyLenHan = 2`), а это самый частый класс канона в китайском ранобэ (蛊, 道, 气); (в) сид-линт об этом молчит. ⚠ Владелец 05.09 отложил гейт до замера ложных срабатываний («если он ложно положительно будет стрелять — это плохо, очень плохо») — вот их источник, и он лечится досевом, а не кодом ⚠ **11.09: это один из ТРЁХ инстансов общего класса — ряд 423** (майнер эмитит только своё поле; на немайненном корпусе меры вырождаются). | бэкенд+полигон | **скоро** | досев форм · `allow_short` у односимвольных · линт сида, который об этом кричит | аудит банка 11.09, `research/34` §2.3 | +| 408 | **ДАННЫЕ БАНКА НЕ ДОСЕЯНЫ, И ИМЕННО ИЗ-ЗА ЭТОГО ГЕЙТ КОНСИСТЕНТНОСТИ НЕЛЬЗЯ ВКЛЮЧИТЬ.** ⛔ **ЧИСЛО ИСПР. 11.09 — ПРЕЖНЕЕ БЫЛО ДО-СТЕММЕРНОЙ БАЗОЙ, а ряд гейтил им решение владельца.** Пере-снято мною прогоном пинов размеченного корпуса (`TM_CHECKER_LABELS=1 go test ./internal/membank/ -run TestK6 -v`): **база (`metrics.json`, до стеммера и до #10) — tp=1 fp=14 ⇒ 0.0667**, и это то, что здесь стояло; **ОТГРУЗОЧНЫЙ путь СЕГОДНЯ — tp=1 fp=6 tn=251 ⇒ 0.1429**; со стеммизацией `decl`-форм — **fp=0 ⇒ 1.0000**. ⚠ И концентрация названа неверно: класса `转` на отгрузочном пути НЕТ ВОВСЕ (его снял стеммер), остаточные шесть — это `元石` ×2 и `蛊虫` ×4, то есть **ровно склонительный разрыв, лечащийся досевом форм**. ⇒ направление ряда верно, величина отставала на два улучшения, а список ложных описывал уже не тот прибор. ⭐ **И это прямо смыкает ряд с 423:** стеммизация `decl`-форм уводит точность в 1.0000, а `decl`-форм нет ни в одной машинной выгрузке — то есть «досеять данные» и есть лечение, но на дорожке продукта досевать некому. Три дыры, все в ДАННЫХ, не в Go: (а) глагольные и многословные термины засеяны с пустыми формами — один `炼化` дал 7 ложных промахов (⚠ **испр. 11.09: это число из ДРУГОГО замера** — `docs/experiments/23-editor-tier.md:7630`=`Все семь «промахов»`, не из `labels/metrics.json`; в размеченном корпусе `炼化` нет вовсе, и обе величины верны порознь, но ссылка была одна на две); (б) односимвольный ханьский ключ структурно вне автомата без `allow_short` (порог 2 знака, `backend/internal/membank/memory.go:72`=`minKeyLenHan = 2`), а это самый частый класс канона в китайском ранобэ (蛊, 道, 气); (в) сид-линт об этом молчит. ⚠ Владелец 05.09 отложил гейт до замера ложных срабатываний («если он ложно положительно будет стрелять — это плохо, очень плохо») — вот их источник, и он лечится досевом, а не кодом ⚠ **11.09: это один из ТРЁХ инстансов общего класса — ряд 423** (майнер эмитит только своё поле; на немайненном корпусе меры вырождаются). | бэкенд+полигон | **скоро** | досев форм · `allow_short` у односимвольных · линт сида, который об этом кричит | аудит банка 11.09, `research/34` §2.3 | | 409 | **РЕДАКТОР — ИСТОЧНИК РАЗНОБОЯ, А НЕ СТРАХОВКА ПОВЕРХ БАНКА, и это замерено дважды.** Без закон-блока редактор ломает 5–12 из 20 уже ВЕРНЫХ клеток черновика (`experiments/18-editor-wire-probe.md` §A.1); с подключённым банком боевой редактор держит ХУДШЕЕ покрытие канона в панели — 0.882 против 0.909 у черновика, который он правит (`experiments/22` §6.2, 1124 упоминания). Два механических носителя: черновая волна выбирает по БАЗОВОМУ банку с исключением намайненного (`bankmaterialize.go:329`) ⇒ на первом прогоне книги черновик идёт вообще без добытого банка; редакторская волна, единственная с полным банком, теряет липкость МЕЖДУ правочными единицами внутри главы (`waverun.go:717`) при **86 % многоединичных глав (1962 из 2283)**. ⇒ закон-блок обязан стать инвариантом конфига, а не следствием выбора модели редактора. ⚠ Инцидентов дрейфа от потери липкости — НОЛЬ наблюдений, замерена только экспозиция: правка без замера была бы стрельбой вслепую. ⛔ **ИСПР. 11.09: «замер снимается прогоном A» назначал работу ЗАКРЫТОМУ прогону.** Прогон A принят актом `D39.247`, зона полигона выведена из скоупа целиком (`D39.248` п.4) — ждать этого замера больше не от кого. **Что прогон A реально дал по предмету — ЭКСПОЗИЦИЯ на живой книге и совпадение при N=1:** манифест дал `docs/experiments/24-door-to-file.md:815`=`units_total 2 / chunks 2` (⚠ испр. 17.09: было :807) у главы 1 при `units_total 1 / chunks 2` у глав 2 и 3, то есть **одна многоединичная глава из трёх**, и единственный термин книги, отданный ДВУМЯ формами (`开窍大典`), стоит обеими формами в ТОЙ ЖЕ главе 1 (`docs/experiments/24-door-to-file.md:334`=`ДВЕ формы, и обе в одной главе` (⚠ испр. 17.09: было :329)). ⚠ **Это наблюдение, а не доказательство:** атрибуция в отчёте доведена до ГЛАВЫ, а не до правочной ЕДИНИЦЫ — переход разнобоя ЧЕРЕЗ границу единицы не показан, и N=1. ⇒ по-юнитный замер дрейфа несёт БЭКЕНД на боевой книге, а решение по липкости принимается ПО ЕГО ИТОГУ: закрытие прогона A убрало исполнителя, а не требование | бэкенд | скоро | закон-блок инвариантом конфига + по-юнитный замер дрейфа на боевой книге и решение по липкости между правочными единицами по его итогу (прогона A ждать нечего — `D39.247`) | аудит банка 11.09, `research/34` §2.4 | -| 410 | ⚠ **ПЕРЕПИСАН 11.09 — ПРЕЖНЯЯ ГОЛОВА БЫЛА НЕВЕРНА. Голос НЕ «мёртв в четырёх местах»: он ПОСТРОЕН СКВОЗЬ И ВЫКЛЮЧЕН ДВУМЯ ТУМБЛЕРАМИ.** Пере-снято мною прибором 11.09. **Построено:** схема сида несёт голос (`internal/seed/seed.go:25`=`Voices []Voice`, `Voices []Voice \`yaml:"voices"\``) · загрузчик секции есть (`membank/memvoice.go:79`=`func loadVoiceSections` `loadVoiceSections`, профиль собирается на `:121`) · хранилище есть (`store.VoiceProfilesForBook`, порядок пинован `bankmaterialize.go:214`) · инъекция в банк построена и УСЛОВНА (`membank/memory.go:511`=`if !in.InjectVoice` по `BankInput.InjectVoice`) · флаггер судит ОТГРУЖЕННЫЙ текст (`pipeline/voicerun.go:42`=`runVoiceChecks runs the voice flagger`) и печатает число в отчёт качества (`backend/internal/pipeline/quality.go:159`=`VoiceFlags int` `voice_flags`) · у гейта есть ручка и потребитель в Go (`quality.go:492`, `voicerun.go:46` по `Gates.Voice.Enabled`). **Выключено ровно двумя вещами.** ⛔ **(1) ДАННЫХ НЕТ НИ ОДНОЙ СТРОКИ, и знаменатель прежней записи был не тот.** Пере-снято: секция `voices:` встречается в **22** файлах дерева, и все 22 ПУСТЫ (не «21 из 22») — но все 22 суть МАШИННЫЕ выгрузки (`*.mined-signature.yaml`, `*.auto-bank.yaml`), то есть их пустота лишь пересказывает «майнер профили не эмитит» и самостоятельной уликой не является. Настоящий знаменатель — **22 рукописных сида с `terms:`, и ключа `voices:` нет НИ В ОДНОМ** (контроль: прибор прочёл 47 файлов с `terms:`, из них 25 машинных отброшены по имени). ⇒ за всю историю проекта профиль голоса не написал никто. **(2) `InjectVoice` — константа `false` без ключа конфига**, и комментарий `pipeline/bankmaterialize.go:295`=`InjectVoice is FALSE and has no config knob` называет и причину (`D21` п.2 держит инъекцию до полигонного замера), и ЦЕНУ включения: «Wiring the injection means setting it and accepting a full --resnapshot». Третьим, помельче: `gates.voice` не выставлен ни в одном из четырёх живых конфигов (контроль: соседние ключи `banknote`, `terminology`, `coverage`, `sanitizer`, `regression_guard` выставлены — прибор спрошен у существующего предмета). ⭐ **ВОПРОС ВЛАДЕЛЬЦУ СНЯТ ЕГО ЖЕ СЛОВОМ 11.09: «Входит»** — голос входит в приоритет №1 наравне с терминами; **проектирует и контролирует голос старший коллега (Fable 5), исполняет опус**, и пак обязан велеть сессии обсудить имплементацию с ним. Второй вопрос связки («если не подпись профилей, то кто») тоже снят: `D39.144` — подписывается банк ЦЕЛИКОМ, пер-профильной подписи в модели продукта нет. ⇒ **строка из вопроса стала ЗАДАЧЕЙ, и она мельче, чем читалась: не «построить голос», а написать профиль, открыть ручку и заплатить ре-снапшотом.** ⚠ Числа у механизма по-прежнему нет ни одного — первый замер обязан идти ПЕРЕД включением | бэкенд/владелец | **скоро** | профиль в сид · ключ конфига вместо константы · замер флаггером по отгруженному тексту; форму проектирует Fable 5 | аудит банка 11.09 (`research/34` §2.5, §4 п.2); голова ИСПР. 11.09 пере-замером оркестратора, слово владельца 11.09 | +| 410 | ⚠ **ПЕРЕПИСАН 11.09 — ПРЕЖНЯЯ ГОЛОВА БЫЛА НЕВЕРНА. Голос НЕ «мёртв в четырёх местах»: он ПОСТРОЕН СКВОЗЬ И ВЫКЛЮЧЕН ДВУМЯ ТУМБЛЕРАМИ.** Пере-снято мною прибором 11.09. **Построено:** схема сида несёт голос (`backend/internal/seed/seed.go:25`=`Voices []Voice`, `Voices []Voice \`yaml:"voices"\``) · загрузчик секции есть (`backend/internal/membank/memvoice.go:79`=`func loadVoiceSections` `loadVoiceSections`, профиль собирается на `:121`) · хранилище есть (`store.VoiceProfilesForBook`, порядок пинован `bankmaterialize.go:214`) · инъекция в банк построена и УСЛОВНА (`backend/internal/membank/memory.go:511`=`if !in.InjectVoice` по `BankInput.InjectVoice`) · флаггер судит ОТГРУЖЕННЫЙ текст (`backend/internal/pipeline/voicerun.go:42`=`runVoiceChecks runs the voice flagger`) и печатает число в отчёт качества (`backend/internal/pipeline/quality.go:159`=`VoiceFlags int` `voice_flags`) · у гейта есть ручка и потребитель в Go (`quality.go:492`, `voicerun.go:46` по `Gates.Voice.Enabled`). **Выключено ровно двумя вещами.** ⛔ **(1) ДАННЫХ НЕТ НИ ОДНОЙ СТРОКИ, и знаменатель прежней записи был не тот.** Пере-снято: секция `voices:` встречается в **22** файлах дерева, и все 22 ПУСТЫ (не «21 из 22») — но все 22 суть МАШИННЫЕ выгрузки (`*.mined-signature.yaml`, `*.auto-bank.yaml`), то есть их пустота лишь пересказывает «майнер профили не эмитит» и самостоятельной уликой не является. Настоящий знаменатель — **22 рукописных сида с `terms:`, и ключа `voices:` нет НИ В ОДНОМ** (контроль: прибор прочёл 47 файлов с `terms:`, из них 25 машинных отброшены по имени). ⇒ за всю историю проекта профиль голоса не написал никто. **(2) `InjectVoice` — константа `false` без ключа конфига**, и комментарий `backend/internal/pipeline/bankmaterialize.go:295`=`InjectVoice is FALSE and has no config knob` называет и причину (`D21` п.2 держит инъекцию до полигонного замера), и ЦЕНУ включения: «Wiring the injection means setting it and accepting a full --resnapshot». Третьим, помельче: `gates.voice` не выставлен ни в одном из четырёх живых конфигов (контроль: соседние ключи `banknote`, `terminology`, `coverage`, `sanitizer`, `regression_guard` выставлены — прибор спрошен у существующего предмета). ⭐ **ВОПРОС ВЛАДЕЛЬЦУ СНЯТ ЕГО ЖЕ СЛОВОМ 11.09: «Входит»** — голос входит в приоритет №1 наравне с терминами; **проектирует и контролирует голос старший коллега (Fable 5), исполняет опус**, и пак обязан велеть сессии обсудить имплементацию с ним. Второй вопрос связки («если не подпись профилей, то кто») тоже снят: `D39.144` — подписывается банк ЦЕЛИКОМ, пер-профильной подписи в модели продукта нет. ⇒ **строка из вопроса стала ЗАДАЧЕЙ, и она мельче, чем читалась: не «построить голос», а написать профиль, открыть ручку и заплатить ре-снапшотом.** ⚠ Числа у механизма по-прежнему нет ни одного — первый замер обязан идти ПЕРЕД включением | бэкенд/владелец | **скоро** | профиль в сид · ключ конфига вместо константы · замер флаггером по отгруженному тексту; форму проектирует Fable 5 | аудит банка 11.09 (`research/34` §2.5, §4 п.2); голова ИСПР. 11.09 пере-замером оркестратора, слово владельца 11.09 | | 411 | ⛔ **КНИГУ, КОТОРУЮ ПАЙПЛАЙН ПЕРЕВОДИТ БЕСПЛАТНО, ПЛАТФОРМА ПРОДАТЬ НЕ МОЖЕТ — и это закрывает деплой на локальном инференсе целиком.** Замерено исполнением на стенде 11.09 (фаза 0 холодного прогона A): на $0-паре `step_max_usd` выходит 0, `ingest.Manifest.priced()` отказывает при `StepMaxUSD <= 0`, старт получает **`409 not_priced`**, в логе ERROR «this book has no price projection, so it cannot be sold». ⇒ **ни одна книга не продаётся, если её перевод ничего не стоит.** Для полигона это обходится номинальной ценой локальной модели отдельным файлом моделей (объявленная девиация), но для ПРОДУКТА это утверждение о рынке: развёртывание на своём железе — а именно им продаётся приватность и дешевизна — сегодня не может принять ни одного заказа. ⚠ Класс ошибки — «ноль цены прочитан как отсутствие цены»: предикат отвечает на свой вопрос («есть ли смета»), а спрошено другое («стоит ли это денег»). Лечение — решение о том, чем платформа меряет продаваемость, а не правка предиката | платформа | скоро | различение «цена ноль» и «сметы нет»; слово о деплое на локальном инференсе | фаза 0 прогона A, 11.09 | | 412 | **ШАБЛОН КНИГИ ИЗ РЕЦЕПТА СТЕНДА РОНЯЕТ КАЖДЫЙ СТАРТ БОЕВОГО КОНФИГА — молча для доков, громко для прогона.** Замерено 11.09: без ключа `langpack_root` движок отказывает на старте с **exit 10** и текстом «gates.terminology is enabled but this book cannot mine a bank: it needs a langpack». Ключа нет ни в `backend/example/book.yaml`, ни в рецепте `platform/docs/STACK_DECISIONS.md` §«Стенд разработчика», ни в рантбуке. ⇒ любой, кто соберёт книгу по нашему же рецепту и включит `c1`, получит отказ на старте — $0 по деньгам, но на ПЛАТНОЙ книге это потерянная «холодность» эксперимента, а на боевой выкатке — невозможность стартовать. Родня строки **251** (артефакт контраста): оба требования боевого банкового контура живут в коде и не доехали до носителей, по которым разворачивают | бэкенд+платформа | скоро | ключ в примере книги и в рецепте стенда; проверка полноты шаблона на буте | фаза 0 прогона A, 11.09 | | 413 | ⛔⛔ **ЧИТАТЕЛЬ ПЛАТИТ ПО НАШЕМУ ПИНУ, А ПИН FLASH ПРОТУХ НА 13 % — и рядом НЕ РАЗРЕШЁННЫЙ вопрос, та ли это вообще модель.** Замерено полигоном на живом платном прогоне 11.09 и пере-проверено вендор-докой дважды (`api-docs.deepseek.com/quick_start/pricing`, гардрейл «идём в официальную доку, не гадаем»): наш пин `backend/configs/models.yaml:228`=`ПИК с 16.08.2026 16:00 UTC` держит flash `$0.44 in / $1.32 out / cache-hit $0.014` от **16.08.2026**, вендорская таблица сегодня даёт **`0.30 / 1.20 / 0.006`**; у `pro` пин совпадает ТОЧНО. Арифметика движка безупречна — по нашему пину прогон сходится до нуля микро-долларов, — но по вендорским числам тот же прогон стоил бы **$0.397246 против $0.419424**, то есть **пин завышает на $0.022177 = 5.6 % книги, ×1.133 по flash**. ⇒ мы выставляем читателю СВОЁ число, и оно выше провайдерского. ⛔ **Половина, без которой цену править НЕЛЬЗЯ:** `model_requested` = `deepseek-v4-flash`, а `model_actual` = **`deepseek-flash`** на 28 строках из 33, и слага `deepseek-flash` в нашем `models.yaml` НЕТ — вендорская прайс-таблица называет модель именно так. По правилу «слаг живой ≠ модель та же» замерено, что имена разные; НЕ установлено, алиас это или другая модель. Сперва identity, потом цена. ⛔ **ДОПОЛНЕНО 11.09 ПЕРЕ-ЗАМЕРОМ ОРКЕСТРАТОРА — под рядом лежит ВТОРАЯ беда, и она про МОЛЧАНИЕ, а не про число.** Замер по всем базам машины ⚠ (контроль ИСПР. 11.09 после пере-замера через `find`: файлов `*.db` **448**, с таблицей `request_log` **405**, прочитано **58 886** строк — первый счёт был занижен `glob`-ом): ⛔ **ЧИСЛА ИСПР. 11.09 — ПРЕЖНИЕ БЫЛИ ЗАВЫШЕНЫ В 10.88 РАЗА МОЕЙ ЖЕ ЛОВУШКОЙ (ряд 428): я опубликовал свод обходом диска, не применив к нему собственную норму.** Контроль честный: баз открыто **449**, строк-экземпляров прочитано **58 886**, **УНИКАЛЬНЫХ строк 5 413** (дедуп по идентичности строки, а не по файлу). После дедупа подстановкой оплачено **70 строк**: боевых **65** — `deepseek-v4-flash` → `deepseek-flash` **28 строк, $0.188953** и `local-qwen3-8b` → `huihui_ai/qwen3-abliterated:8b` **37 строк, $0**; фикстур **5** на **$0.424277** (`m-req`→`m-act` 1, `fake-model` 4). ⚠ Прежние «365 · 344 · 21 · $2.049737 · вычесть $5.51» — все одиннадцатикратные, ни одно за результат не принимать — провайдер вернул слаг, которого в каталоге нет, — `deepseek-v4-flash` → `deepseek-flash` (296 строк, $2.049737) и `local-qwen3-8b` → `huihui_ai/qwen3-abliterated:8b` (48 строк, $0). **Сегодня это безвредно:** подстановка падает на ЗАПРОШЕННУЮ модель той же семьи, и пин верен по семье. ⛔ Опасна не подстановка, а то, что о ней **никто не узнаёт**: `PriceForResponse` (`backend/internal/ledger/pricing.go:88`=`func (p *Pricer) PriceForResponse`) пробует `actual`, потом `requested`, потом якорь, и ни одно из ТРЁХ мест вызова не различает, какая ветвь сработала. Комментарий там же охраняет РОВНО ОДНО направление («премиальный ответ не должен биться по дешёвому дефолту»); обратное — когда провайдер маршрутизирует ВНИЗ — не охраняет никто: запрошен `pro`, ответила модель дешевле, счёт идёт по пину `pro`, $3.96 за 1M выходных против $1.20 вендорских у flash = **×3.3 из кармана читателя, молча**. ⇒ лечение двухчастное: завести слаг, который провайдер РЕАЛЬНО возвращает, и сделать срабатывание подстановки ВИДИМЫМ. Носитель работы — пак «падение, которое видно» §4.5. ⚠ **Адресат ИСПР. 11.09: полигон выведен из скоупа, и `D39.248` п.4 называет ЭТОТ ряд работой ДРУГИХ зон поимённо** — обе половины движковые: слаг живёт в `backend/configs/models.yaml`, видимость подстановки — в `backend/internal/ledger/pricing.go` | бэкенд | **скоро** | вендор-сверка identity слага, затем пере-пин с датой и способом в формулировке; отдельно — наблюдаемость подстановки | критик чисел прогона A, 11.09; подстановка — пере-замер оркестратора 11.09 | @@ -333,27 +333,27 @@ | 420 | ⛔ **`unit_done` ВСТАВЛЕННОЙ ГЛАВЫ НЕ ОБЪЯВЛЯЕТСЯ ВОВСЕ — тихая потеря доставки за швом.** Найдено дизайн-паком перекроя 11.09 при инвентаре чужой стороны: ключ объявления несёт ОРДИНАЛ (`backend/internal/pipeline/events.go`, греп `once_key`), отказ молчалив (греп `outbox`), а `deliveredUnits` считает юнит доставленным. ⇒ при вставке главы читатель не получает объявления о доставке, и никто этого не замечает. **Это не перепокупка, а потеря СОБЫТИЯ**; чинится в движке. ⚠ Единственная настоящая потеря за швом из всего, что дизайн проверил: остальные четыре его подозрения оказались «уже построено» на стороне платформы | бэкенд | скоро | объявление доставки, переживающее вставку главы | дизайн-пак перекроя, 11.09 | | 421 | **ЗАМЕР, РАДИ КОТОРОГО ШЕСТОЙ ВОПРОС СНЯТ С ВЛАДЕЛЬЦА: сколько банк-батчей на боевой книге двигает ТОЛЬКО окно.** Дизайн-пак завёл вопрос о проводе банк-ролей и САМ его снял с владельца доводом «цена меняла знак ТРИЖДЫ — 11 % всегда → ноль → интервал от нуля до всего прохода; число, трижды менявшее знак, владельцу отдавать нельзя». Постановка готова: считать на боевой книге долю батчей, у которых меняется только окно `since_ch`/`until_ch`, и тем закрыть интервал. ⚠ **Ряд заведён 11.09 по находке аудита: и дизайн, и акт `D39.245` объявляли замер «ушедшим в бэклог», а в бэклоге его НЕ БЫЛО** — классический случай «заведено» со слов, без грепа по живому трекеру | бэкенд/полигон | когда-нибудь | доля батчей, двигающих только окно, числом на боевой книге | дизайн-пак перекроя 11.09, заведён аудитом смены | | 422 | ⛔ **КОЛОНКА, КОТОРОЙ СПРАШИВАЮТ «СКОЛЬКО СЪЕЛО ДУМАНЬЕ», НЕ НЕСЛА ЧИСЛА НИ РАЗУ ЗА ВСЮ ИСТОРИЮ ПРОЕКТА.** Замер 11.09 оркестратором: `request_log.reasoning_tokens > 0` — **0 строк**; контроль рядом, доказывающий, что вопрос задан существующему предмету: ⚠ **контроль ИСПР. 11.09 — мой первый счёт был занижен: `glob` пропустил ~170 баз, пере-снято через `find`** — файлов `*.db` найдено **449**, прочитано **58 886** строк-экземпляров, **УНИКАЛЬНЫХ строк 5 413** (⛔ испр. 11.09: прежний знаменатель сам был умножен копиями в 10.88 раза — ряд **428**; ноль устоял и на честном знаменателе). Колонка объявлена схемой (`backend/internal/store/migrate.go`, блок `CREATE TABLE request_log`) и присутствует во всех. ⇒ **единственная колонка, которой можно доказать «потолок съело рассуждение», структурно молчит**, и её ноль неотличим от «думанья не было». Прямо это и есть слепота в вопросе владельца «мы ждали 249 секунд и заплатили за ничего»: у DeepSeek рассуждение считается ВНУТРИ `completion_tokens` и отдельным полем не приходит, поэтому на провальных вызовах прогона A видно `completion_tokens` 8496 · 8496 · 8496 · 16000 при нуле знаков текста — то есть потолок выкуплен целиком, а чем — не сказано ничем. ⚠ Родня рядов **414** (признак отказа не в той колонке) и **415** (четверть денег за пустоту): все три — про то, что ОТКАЗ и его ПРИЧИНА не доезжают до прибора, которым смотрят деньги | бэкенд | **скоро** | поле, различающее «рассуждение съело потолок» и «рассуждения не было» — из тела ответа провайдера, а не из отсутствующего поля usage; либо явная пометка «провайдер не сообщает» | пере-замер оркестратора 11.09 по базе прогона A | -| 423 | ⛔⛔ **МАЙНЕР ЭМИТИТ ТОЛЬКО ТО ПОЛЕ, РАДИ КОТОРОГО ПОСТРОЕН, И КАЖДЫЙ МЕХАНИЗМ НИЖЕ ПО ТЕЧЕНИЮ, КОТОРОМУ НУЖНЫ ДАННЫЕ БОГАЧЕ, ТИХО ДЕГРАДИРУЕТ. Три открытых ряда оказались ОДНИМ классом.** Пере-замер 11.09 по `books/` (контроль: прибор распарсил **153** yaml-файла, сбоев разбора 0; непустой `terms:` у **34** файлов — 2471 терм; проходящий фильтр рядом с нулём: непустой `dst` несут **2419 из 2471** термов, то есть тела термов прибор читает): ненулевые `decl.forms` есть ТОЛЬКО там, где их писал человек, и носителей ШЕСТЬ, а не три — `guzhenren-seed-v2.yaml` 42 терма из 58 · `diag/guzhenren-seed-v2.pre-reseed.yaml` 41 из 57 · `exp15/guzhenren-seed-v2.pre-gender.yaml` 41 из 57 · `rerun2/guzhenren-seed-rerun2.yaml` 41 из 57 · `guzhenren-seed.yaml` 35 из 49 · `minirun/mined-delta.yaml` 2 из 2 (дельта mining-stop с подписью владельца — рукопись, несмотря на имя `mined-`); седьмой носитель лежит ВНЕ книг и к дорожке продукта отношения не имеет — golden-фикстура `backend/internal/pipeline/testdata/golden/glossary-seed.yaml` 4 из 5. **Во ВСЕХ 26 машинных файлах (2187 термов) — ноль, и это не разреженность, а отсутствующее поле**: 25 выгрузок `*.mined-signature.yaml`/`*.auto-bank.yaml` несут `decl: null` у ВСЕХ своих 2126 термов — 0 из 142 (два файла) · 0 из 102 (ЧЕТЫРНАДЦАТЬ файлов) · 0 из 83 · 0 из 76 · 0 из 74 · 0 из 69 (банк платного прогона A) · 0 из 53 (два файла) · 0 из 3 · 0 из 2 · 0 из 1; а сид-дельта `design11/ws3_seed_delta.yaml` (0 из 61) ключа `decl` не пишет ВООБЩЕ — её эмитит скрипт полигона `eval/design11/ws3_seeddelta.py`, и все 61 терма помечены им как `mined draft`/`mined WHICH-only auto-candidate`. Рукописных нулей два, и они ДРУГОЙ природы: `rerun2/mined-delta.yaml` 0 из 3 и `minirun-verify2/mined-delta.yaml` 0 из 1 — там `invariant: true, forms: []`, то есть поле заполнено осознанно. ⚠ Эррата к первой редакции ряда (числа не воспроизвелись, вывод устоял и усилился): «47» было числом файлов с КЛЮЧОМ `terms:` по ВСЕМУ репозиторию (35 непустых + 12 пустых `mined-delta.yaml`), а не с непустым `terms:`; «0 из 102 (шесть раз)» — на деле четырнадцать файлов; «0 из 67» носителя не имеет вовсе; носителей форм шесть, а не три. ⚠ Машинное от рукописного по ИМЕНИ файла не отличается — обманывает в обе стороны: `minirun/mined-delta.yaml` с машинным именем подписан владельцем, а `ws3_seed_delta.yaml` без машинного имени эмитирован скриптом; судить только содержимым. ⇒ **на книге без рукописного сида — то есть на нормальной дорожке продукта — пост-проверке нечем опереться, кроме глобального одношагового стеммера**, и это ровно тот механизм, который ряд **419** замерил как дающий 11 ложных тревог из 18. Три инстанса одного класса: `decl.forms` (`internal/seed/seed.go:87`=`type Decl struct`, потребитель `membank/memory.go:342`=`Parse decl forms for the post-check`) · профили голоса (ряд **410**: `voices:` пуст во ВСЕХ 22 машинных выгрузках и отсутствует во ВСЕХ 22 рукописных сидах) · формы глагольных и многословных термов (ряд **408**). ⭐ **Ценность ряда в том, что он снимает три отдельные «доработки данных» и ставит один вопрос: что банк обязан отдавать, кроме пары «исходник → передача», чтобы механизмы ниже работали не вырожденно.** ⚠ Это НЕ заказ «научить майнер всему»: часть полей модель предложить не может в принципе (склонение — да, голос — спорно), и разделение «что майнится · что сеется человеком · что вычисляется из языка» и есть предмет. ⛔ Пока ряд открыт, любой замер точности пост-проверки на РУКОПИСНОМ корпусе меряет исключение, а не правило — этим 11.09 ошибся оркестратор, решая порядок колонок прибора консистентности | бэкенд | **скоро** | разделение «майнится · сеется · выводится из языка» + носитель того, чего майнер не даёт | пере-замер оркестратора 11.09 по числу зоны `textmachine-c9` | +| 423 | ⛔⛔ **МАЙНЕР ЭМИТИТ ТОЛЬКО ТО ПОЛЕ, РАДИ КОТОРОГО ПОСТРОЕН, И КАЖДЫЙ МЕХАНИЗМ НИЖЕ ПО ТЕЧЕНИЮ, КОТОРОМУ НУЖНЫ ДАННЫЕ БОГАЧЕ, ТИХО ДЕГРАДИРУЕТ. Три открытых ряда оказались ОДНИМ классом.** Пере-замер 11.09 по `books/` (контроль: прибор распарсил **153** yaml-файла, сбоев разбора 0; непустой `terms:` у **34** файлов — 2471 терм; проходящий фильтр рядом с нулём: непустой `dst` несут **2419 из 2471** термов, то есть тела термов прибор читает): ненулевые `decl.forms` есть ТОЛЬКО там, где их писал человек, и носителей ШЕСТЬ, а не три — `guzhenren-seed-v2.yaml` 42 терма из 58 · `diag/guzhenren-seed-v2.pre-reseed.yaml` 41 из 57 · `exp15/guzhenren-seed-v2.pre-gender.yaml` 41 из 57 · `rerun2/guzhenren-seed-rerun2.yaml` 41 из 57 · `guzhenren-seed.yaml` 35 из 49 · `minirun/mined-delta.yaml` 2 из 2 (дельта mining-stop с подписью владельца — рукопись, несмотря на имя `mined-`); седьмой носитель лежит ВНЕ книг и к дорожке продукта отношения не имеет — golden-фикстура `backend/internal/pipeline/testdata/golden/glossary-seed.yaml` 4 из 5. **Во ВСЕХ 26 машинных файлах (2187 термов) — ноль, и это не разреженность, а отсутствующее поле**: 25 выгрузок `*.mined-signature.yaml`/`*.auto-bank.yaml` несут `decl: null` у ВСЕХ своих 2126 термов — 0 из 142 (два файла) · 0 из 102 (ЧЕТЫРНАДЦАТЬ файлов) · 0 из 83 · 0 из 76 · 0 из 74 · 0 из 69 (банк платного прогона A) · 0 из 53 (два файла) · 0 из 3 · 0 из 2 · 0 из 1; а сид-дельта `design11/ws3_seed_delta.yaml` (0 из 61) ключа `decl` не пишет ВООБЩЕ — её эмитит скрипт полигона `eval/design11/ws3_seeddelta.py`, и все 61 терма помечены им как `mined draft`/`mined WHICH-only auto-candidate`. Рукописных нулей два, и они ДРУГОЙ природы: `rerun2/mined-delta.yaml` 0 из 3 и `minirun-verify2/mined-delta.yaml` 0 из 1 — там `invariant: true, forms: []`, то есть поле заполнено осознанно. ⚠ Эррата к первой редакции ряда (числа не воспроизвелись, вывод устоял и усилился): «47» было числом файлов с КЛЮЧОМ `terms:` по ВСЕМУ репозиторию (35 непустых + 12 пустых `mined-delta.yaml`), а не с непустым `terms:`; «0 из 102 (шесть раз)» — на деле четырнадцать файлов; «0 из 67» носителя не имеет вовсе; носителей форм шесть, а не три. ⚠ Машинное от рукописного по ИМЕНИ файла не отличается — обманывает в обе стороны: `minirun/mined-delta.yaml` с машинным именем подписан владельцем, а `ws3_seed_delta.yaml` без машинного имени эмитирован скриптом; судить только содержимым. ⇒ **на книге без рукописного сида — то есть на нормальной дорожке продукта — пост-проверке нечем опереться, кроме глобального одношагового стеммера**, и это ровно тот механизм, который ряд **419** замерил как дающий 11 ложных тревог из 18. Три инстанса одного класса: `decl.forms` (`backend/internal/seed/seed.go:87`=`type Decl struct`, потребитель `backend/internal/membank/memory.go:342`=`Parse decl forms for the post-check`) · профили голоса (ряд **410**: `voices:` пуст во ВСЕХ 22 машинных выгрузках и отсутствует во ВСЕХ 22 рукописных сидах) · формы глагольных и многословных термов (ряд **408**). ⭐ **Ценность ряда в том, что он снимает три отдельные «доработки данных» и ставит один вопрос: что банк обязан отдавать, кроме пары «исходник → передача», чтобы механизмы ниже работали не вырожденно.** ⚠ Это НЕ заказ «научить майнер всему»: часть полей модель предложить не может в принципе (склонение — да, голос — спорно), и разделение «что майнится · что сеется человеком · что вычисляется из языка» и есть предмет. ⛔ Пока ряд открыт, любой замер точности пост-проверки на РУКОПИСНОМ корпусе меряет исключение, а не правило — этим 11.09 ошибся оркестратор, решая порядок колонок прибора консистентности | бэкенд | **скоро** | разделение «майнится · сеется · выводится из языка» + носитель того, чего майнер не даёт | пере-замер оркестратора 11.09 по числу зоны `textmachine-c9` | | 424 | **ТРИНАДЦАТЬ РЯДОВ ТРЕКЕРА РЕНДЕРЯТСЯ С ЛИШНИМИ КОЛОНКАМИ — неэкранированный `\|` внутри ячейки, обычно в код-спане вида `auto\|draft\|approved`.** Замер 11.09 ТЕМ ЖЕ расщепителем, что у гейта (контроль: рядов прочитано **303**, целых **290**, сломанных **13**): 163 · 182 · 248 · 127 · 279 · 306 · 311 · 320 · 346 · 361 · 378 · 389 · 407. ⛔ **Первая редакция называла ЧЕТЫРНАДЦАТЬ и включала ряд 253 — это была ошибка ПРИБОРА, а не находка: я считал разделители наивно, а 253 их ЭКРАНИРУЕТ, и расщепитель гейта видит его целым.** Хуже: ошибка уехала В САМ ГЕЙТ — 253 попал в `SHAPE_GRANDFATHERED` и ослепил проверку на неcломанном ряде навсегда; снят 11.09. ⇒ **урок дороже ряда: контроль снимается ТЕМ ЖЕ прибором, которым судит гейт, иначе дедовщина консервирует не долг, а мой промах.** Лечение — `\|` в ячейке; работа механическая. ⭐ **Ряд заведён не ради косметики, а потому что гейт этого НЕ ВИДЕЛ, и слепота стоила инцидента:** проверка формы в `docs/scripts/counts.py` ловила только «колонок МЕНЬШЕ ожидаемого», а «больше» и «текст за последним разделителем» молчали — и ряд **406** прожил от создания до 11.09 с **1044 знаками текста ВНЕ таблицы**, при этом счётчики сходились (они читают ячейки с конца и попадали в нужные) и гейт был зелён. Проверка сделана симметричной тем же днём, эти 14 внесены в `SHAPE_GRANDFATHERED` по конвенции файла «гейт рождается зелёным на известном долге и краснеет на следующем»; три посадки на копии подтвердили, что обе новые половины краснеют ПО ТЕКСТУ, а дедовщина молчит. ⇒ закрытие ряда = экранировать 14 ячеек и вынести их из списка | оркестратор | когда-нибудь | экранирование `\|` в четырнадцати ячейках и пустой `SHAPE_GRANDFATHERED` | структурная проверка оркестратора 11.09 | | 425 | **ПРИБОР КОНСИСТЕНТНОСТИ СЛЕП ПО ПОСТРОЕНИЮ В ШЕСТИ МЕСТАХ, и ни одно не чинится матчером.** Названо зоной 11.09 на прямой вопрос «что ты знаешь и не сказала» — до вопроса была названа ОДНА. **(1)** передача, СОДЕРЖАЩАЯ форму банка целиком, и есть эта форма (`开窍大典`) — единственное расхождение с ручным оракулом, где прибор слеп структурно; **(2)** омонимы по `sense`: одно вхождение засчитывается КАЖДОМУ ряду с тем же ключом, и обе строки полисемичного терма покрытыми быть не могут (латентно: 69 различных `src` на 69 рядов); **(3)** ⛔ общеупотребительная передача вдали от своего термина маскирует настоящее отсутствие — `魔道` даёт `fired=1` при счёте 3; **сдвиг ОДНОСТОРОННИЙ, в сторону благополучия ⇒ `I2` есть НИЖНЯЯ граница, а не оценка**, и число уже печатается строкой «terms found MORE often than their key fired» (на прогоне A 9 и 7); **(4)** гранулярность — ЮНИТ, а не вхождение: «форма на месте срабатывания» требует выравнивания исходника с целью; **(5)** термин, которого в банке НЕТ, невидим вовсе — молчание неотличимо от успеха; **(6)** вторая форма НЕ НАЗЫВАЕТСЯ никогда: I1 ловится отсутствием банковской формы, а не узнаванием того, что стоит вместо неё. ⇒ **(1) и (6) закрываются ОДНИМ заказом — каналом `variants` в БД**; (3) закрыто числом рядом с `I2` | бэкенд | скоро | канал `variants` закрывает (1) и (6); прочее — объявленные свойства, пере-открывать замером | зона пака консистентности 11.09, секция «где прибор слеп и я это знаю» | | 426 | **ГРАНИЦЫ НОРМАЛИЗАЦИИ И РАВЕНСТВА — три, все с числом.** **(1)** граница АБЗАЦА не видна: `NormalizeTargetForm` сворачивает любой пробельный ряд в один пробел, поэтому разрыв абзаца без конечной пунктуации неотличим от пробела; граница ПРЕДЛОЖЕНИЯ закрыта и пинована, а видеть абзац значит завести ВТОРОЙ нормализатор, расходящийся с пост-проверкой. **(2)** строгая колонка не в точности равна `dstFormPresent` в ОБЕ стороны — слова против рун: пунктуация внутри формы (**23 расхождения на 30 000 троек**) и форма без букв; недостижимо на банке без `decl`-форм, то есть на ЛЮБОМ машинном (ряд **423**). **(3)** ⛔ **точность самого отношения `NearStems` ≈ 0.57** — 17 из 30 равномерной выборки принятых пар (`рода~родной`, `гор~горная`, `так~также` — разные леммы) ⇒ **работает не отношение, а ограждения** (якорь · многословное окно · границы предложения), и их эффективность замерена на ОДНОЙ книге; названный отказ — слово банковской передачи оказывается соседом ДРУГОГО слова в той же позиции окна, и колонка врёт в сторону сокрытия | бэкенд | скоро | (3) — вторая книга либо размеченные пары лемм; (1) и (2) — объявленные свойства | зона пака консистентности 11.09 | | 427 | ⛔ **СТУПЕНЬ ТОЧНОСТИ ПРИБОРА НЕ ЗАЩИЩЕНА НИ НА ОДНОЙ МАШИНЕ, КРОМЕ ЭТОЙ.** Корпусные пины (`TestK6*`, `TestTheInstrumentAgainstTheColdRunOracle`) держатся только там, где есть дерево `books/`; здесь они идут и несущие в гейте, но **до первого гейта на другой машине или в CI ступень точности не защищена ничем**. ⚠ Различать надо две ступени, и первая цела: **механизм первичного вердикта защищён ГЕРМЕТИЧНО** — пять синтетических пинов краснеют без дерева книг (проверено посадкой четырёх мутаций дважды: «4 mutation(s) run, 0 unexpected»). Корпусные защищают ТОЧНОСТЬ, и это вторая ступень. Смягчение уже построено зоной: `backend/Makefile` цель `mutations` экспортирует абсолютные пути к корпусу, `battery-stand` форсирует `TM_CHECKER_LABELS=1` — отсутствие данных там ПАДАЕТ, а не скипает. ⇒ остаток ряда: что делает CI, у которого дерева книг нет по построению | бэкенд+оркестратор | скоро | решение по корпусу в CI: везти, генерировать или объявить ступень машино-зависимой | зона пака консистентности 11.09, проход старшего коллеги исполнением | | 428 | ⛔ **ЧЕТВЁРТАЯ ЛОВУШКА ДЛЯ СЧИТАЮЩИХ ДЕНЬГИ, и она умножает счёт на число КОПИЙ базы.** Замер оркестратора 11.09 при приёмке (контроль: `find` дал **449** файлов `*.db`, таблицу `spend` несут **406**, строк `spend` — **295**, различных дат — 18): сумма `committed_usd` по всем базам машины за 11.09 даёт **$4.354443 на 13 строках**, тогда как настоящая трата дня — **$0.419423 ОДИН раз**. Разница — не ошибка движка: таблица `spend` ключуется `(book_id, date)` и переезжает вместе с файлом, а рабочая сессия сделала девять копий базы прогона (`runA`, `runA-frozen`, `dbcopy`, обзорные копии, пред-миграционные бэкапы) — **одна и та же строка сосчиталась десять раз**. Плюс промежуточный бэкап на $0.16021 добавил одиннадцатый счёт того же прогона в другой момент времени. ⛔ **И тем же множителем больна ВТОРАЯ таблица, что я обнаружил только пере-замером по наводке аудита: `request_log` — 58 886 строк-экземпляров на 449 базах суть **5 413 УНИКАЛЬНЫХ**, множитель **10.88×**.** Я опубликовал по нему числа подстановки цены (ряд 413) и контроль ряда 422, не применив к ним собственную норму из ЭТОГО ряда — между заведением нормы и её нарушением прошёл час. ⇒ **любой денежный свод, собранный обходом файлов по диску, завышает трату кратно числу копий**, и это первое, к чему потянется рука при вопросе «сколько мы потратили за день». ⚠ Родня трёх ловушек акта `D39.247` п.5 (`run_attempts.spend_micro_usd` накопленная · `err` пуст на провалах · `chunk_status` недобирает терминологию) — у всех один класс: **прибор денег отвечает на вопрос, которого ему не задавали.** Лечение — не код, а норма свода: деньги считаются по УНИКАЛЬНОМУ `(book_id, date)` либо по одной авторитетной базе, и рядом печатается, сколько файлов прибор обошёл | оркестратор | скоро | норма денежного свода в ролевом промте + дедупликация по `(book_id, date)` | приёмка пака консистентности, 11.09 | -| 429 | **БОЕВОЙ КОНФИГ НЕСЁТ ОТОЗВАННЫЙ ВЕНДОРСКИЙ КЛЕЙМ, И ЧИТАТЕЛЬ ЕМУ ВЕРИТ.** `backend/configs/pipeline-c1.yaml:86`=`v4-pro maps low` дословно: «v4-pro maps low→high, effective effort unchanged». Это было верно до 30.08 и **ОТОЗВАНО**: вендор сменил маппинг (`docs/experiments/00-provider-quirks.md` §3а — таблица теперь ОДНА на обе модели, `low→low`), и поведенческая проба полигона 30.08 за $0.038276 показала, что `low` до `pro` ДОХОДИТ. ⇒ комментарий в дереве утверждает ровно обратное живой правде, и стоит он в том самом файле, который промты велят читать. ⚠ Цена не гипотетическая: на этом клейме строилась оценка «ручки у редактора нет вовсе», и она уже уводила решение. ⛔ **Класс шире одной строки: вендорский факт, вмороженный в комментарий, протухает молча — у комментария нет ни даты, ни гейта, ни владельца.** Лечение узкое — привести строку в соответствие; лечение широкое — правило, по которому вендорский факт в коде несёт дату снятия и указатель на квирки, а не живёт вечно | бэкенд | скоро | правка строки 86 + правило «вендорский факт в комментарии несёт дату и адрес» | аудит смены 11.09 | +| 429 | **БОЕВОЙ КОНФИГ НЕСЁТ ОТОЗВАННЫЙ ВЕНДОРСКИЙ КЛЕЙМ, И ЧИТАТЕЛЬ ЕМУ ВЕРИТ.** `backend/configs/pipeline-c1.yaml:88`=`v4-pro maps low` дословно: «v4-pro maps low→high, effective effort unchanged». Это было верно до 30.08 и **ОТОЗВАНО**: вендор сменил маппинг (`docs/experiments/00-provider-quirks.md` §3а — таблица теперь ОДНА на обе модели, `low→low`), и поведенческая проба полигона 30.08 за $0.038276 показала, что `low` до `pro` ДОХОДИТ. ⇒ комментарий в дереве утверждает ровно обратное живой правде, и стоит он в том самом файле, который промты велят читать. ⚠ Цена не гипотетическая: на этом клейме строилась оценка «ручки у редактора нет вовсе», и она уже уводила решение. ⛔ **Класс шире одной строки: вендорский факт, вмороженный в комментарий, протухает молча — у комментария нет ни даты, ни гейта, ни владельца.** Лечение узкое — привести строку в соответствие; лечение широкое — правило, по которому вендорский факт в коде несёт дату снятия и указатель на квирки, а не живёт вечно | бэкенд | скоро | правка строки 86 + правило «вендорский факт в комментарии несёт дату и адрес» | аудит смены 11.09 | | 430 | **ОПЕРАЦИОННЫЙ ДОЛГ СМЕНЫ 11.09, У КОТОРОГО НЕ БЫЛО НОСИТЕЛЯ НИГДЕ — заведён аудитом.** **(а) Стенд платного прогона A оставлен ПОДНЯТЫМ полигонной сессией и жив вторые сутки:** `tmplatformd` уже мёртв, но кластер postgres работает (`~/.local/share/tmstand/pgdata`, сокет `/tmp:55433`, ~245 МБ на девяти процессах — замерено `ps`). ⛔ **Гасить СЕЙЧАС нельзя, и это решение, а не забывчивость:** бэкенд-батарея без живого postgres СКИПАЕТ денежные пути (замерено при приёмке прогона A: первая «зелень» имела 420 пропущенных тестов, все «нет живого Postgres»), а её финальный гейт идёт прямо сейчас. ⇒ гасить ПО PID после закрытия бэкенд-пака актом; полигонная сессия велела «только по pid», и это верно — на машине живут чужие прогоны. **(б) Улики прогона A закоммичены (`ef0509f`, 33 файла) и НЕ ОТПРАВЛЕНЫ:** репозиторий книг на один коммит впереди `origin/main`, санкция владельца получена 11.09 («Да»), выполнить пуш должен он у себя — мой классификатор прав это действие не пропускает. ⇒ **единственная копия улик платного прогона живёт на ОДНОЙ машине.** ⚠ Класс обоих: операционное состояние, о котором знают только участники разговора, носителем не является — ровно тот класс, что эта смена ловила у себя дважды | оркестратор/владелец | **скоро** | (а) гашение по pid после акта; (б) `git -C books push origin HEAD` — действие владельца | аудит смены 11.09 | | 431 | ⛔ **СЕССИИ ЗОН НЕ МОГУТ СНЯТЬ ПОЛНЫЙ МУТАЦИОННЫЙ КАТАЛОГ ПО СРЕДЕ, А ОРКЕСТРАТОР МОЖЕТ — и это делает «оркестратор добирает за зону» НОРМОЙ ПО УМОЛЧАНИЮ.** Замер 11.09: бэкенд-сессию убило ЧЕТЫРЕ раза подряд на пере-снятии десяти записей (дважды 0 из 10, падало на первой). Причина — не машина и не нагрузка: `dmesg` даёт **26** убийств, **все с `constraint=CONSTRAINT_MEMCG`**, каждое в своём транзиентном юните `tm.slice/tm-runs.slice/tm-test-*`; сами слайсы при этом `memory.max = max`. А прогон оркестратора идёт в `/init.scope` с `memory.max = max` и доходит до конца (проверено: тот же каталог, та же команда, 10 из 10 сняты). ⇒ **разница не в умении, а в СКОУПЕ**, и пока она есть, полный каталог структурно может снять только оркестратор. ⛔ **Цена этого — ползучая подмена рубежа:** приёмка обязана СУДИТЬ чужую работу, а не производить её измерения; если зона по среде не может снять свой главный гейт, то «пере-снял своим прибором» (норма) незаметно превращается в «сделал за неё» (подмена). ⭐ Различение, которым это лечится, ратифицируется актом пака консистентности: **пере-снял = повторил ИМЕЮЩЕЕСЯ измерение зоны; сделал за неё = произвёл измерение, которого у зоны НЕТ, и вписал как её.** ⛔ **И ВТОРАЯ ПОЛОВИНА, названная САМОЙ ЗОНОЙ, без которой ряд лечит не то: дело не только в потолке.** Её слова: даже без потолка она потеряла бы прогон ДВАЖДЫ — первый раз потому, что пустила второй мутатор по чужому корню, второй раз потому, что `diff -rq` убедил её, будто результаты целы. ⇒ **из четырёх потерь две — СРЕДЫ, две — МЕТОДА.** Ряд обязан ловить оба: «зона не может снять свой гейт по среде» И «зона портит собственный гейт методом». Иначе потолок починят и удивятся, что не помогло. ⇒ лечение по существу: поднять потолок транзиентных юнитов до замеренного пика `tmmutate` ЛИБО гонять полный каталог в скоупе без потолка объявленно, с числом из `dmesg` рядом — но не оставлять это молчаливым свойством среды | оркестратор/владелец | **скоро** | потолок юнитов поднят до замеренного пика ЛИБО объявлено, что полный каталог снимает оркестратор, и почему | замер оркестратора 11.09, разбор со старшим коллегой | | 432 | **СТЕНД-СТУПЕНЬ ГЕЙТА НЕ МОЖЕТ БЫТЬ ЗЕЛЁНОЙ НА ЭТОМ ХОСТЕ: одному её измерению нужны данные, которые НАМЕРЕННО не версионируются, и после вывода полигона из скоупа их некому доставить.** Замер 11.09 при приёмке: `TM_MINER_PARITY=1 go test -race ./internal/miner/` даёт FAIL с текстом «required data is missing: `eval/exp16/data/jieba_dict_general_zh.txt`» — и в МОЕЙ копии, и в НАСТОЯЩЕМ дереве. Причина названа самим репозиторием: `.gitignore:39` исключает `eval/exp16/data/` с комментарием «exp16 versioned contrast corpus (jieba 0.42.1 dict.txt, 5MB) — SHA pinned in the report, reproducible». ⇒ **это НЕ дефект пака и НЕ дефект дерева**, а дыра провизионирования: флаг `TM_MINER_PARITY=1` по замыслу превращает скип в падение («missing data FAILS instead of skipping»), и на хосте, куда корпус не доставляли, он падает по назначению. ⚠ **Вторая половина хуже первой: владельцем `eval/` был полигон, а зона выведена из скоупа (`D39.248`)** — значит доставлять корпус теперь некому, и ступень будет падать у каждого, кто исполнит рецепт. ⭐ Различать надо ДВА измерения стенда: **корпус разметки** (`books/gu-zhenren/labels`, 6 записей) — на месте, ступень идёт, и именно она защищает прибор консистентности; **контраст майнера** — отсутствует. ⇒ закрытие ряда: либо рецепт доставки корпуса с пинованным SHA в носителе стенда, либо честное объявление «измерение контраста майнера на этом развёртывании не бежит», но не молчаливое красное | бэкенд/оркестратор | **скоро** | рецепт доставки корпуса ЛИБО объявленное отсутствие измерения | приёмка пака консистентности, 11.09 | | 433 | ⛔ **ЛЕКАРСТВО ОТ ДВОЙНОЙ ОПЛАТЫ ПОСТРОЕНО И СТОИТ ВЫКЛЮЧЕННЫМ — и помогает ОДНОМУ случаю из четырёх.** Пак 11.09 закрыл НАБЛЮДАЕМОСТЬ (видно, сколько и на что) и построил ЛЕЧЕНИЕ (ступень усилия ниже при том же бюджете на классе `FlagEmpty`), но ручка `retries.lower_effort_on_empty` лендится с дефолтом `false`: **деньги продолжают течь**, и ничто в дереве этого не остановит, пока ключ не поставят в `true`. ⚠ Дефолт выбран не из робости: включение двигает форму попытки ≥1, а бамп версии политики потолка стоил бы пере-перевода **989 единиц на 24 книгах, $9.99 уже оплаченного** (дедуплицированный замер зоны). ⛔ **И охват уже — из четырёх двойных оплат прогона A лекарство достаёт ОДНУ:** `edit` ($0.071009 = 67 % потери) стоит на `off`, у которого шаг вниз есть; три черновых ($0.035463 = 33 %) уже на `low` — **дне эмитирующей шкалы, и лекарства для них в паке НЕТ**. ⇒ условие включения одно и измеримое: **эхо-контроль ИМЕННО В РЕДАКТОРСКОЙ РОЛИ на плотном CJK, парным дизайном на повторах.** ⚠ Прежняя оценка риска цитировала НЕ ТУ РОЛЬ: «1 чистый китайский выход из 16» — это `flash` как ПЕРЕВОДЧИК, а единственная стадия, которую ручка двигает, — РЕДАКТОР, и квирки прямо говорят, что его эхо-безопасность при `low` на CJK **не мерена**. Ошибку нашёл направленный читатель зоны, не я и не она. ⚠ Вторичный исход того же замера, стоящий $0 сверх прогона: **растёт ли размышление вместе с потолком на `low`** — ровно тот вопрос, который `D39.90` п.9 объявил непроверенным, и он решает, рычаг ли флор | бэкенд/владелец | **скоро** | эхо-контроль в РЕДАКТОРСКОЙ роли на CJK ⇒ ручка в `true`; плюс лечение для дна шкалы | пак «за одну единицу платим дважды», 11.09 | | 434 | ⛔ **ПРИБОР КОНСИСТЕНТНОСТИ НЕ НАХОДИТ ПЕРЕДАЧУ У 26 ТЕРМОВ ИЗ 69 И МОЛЧА СЧИТАЕТ ИХ КОНСИСТЕНТНЫМИ.** Замер оркестратора 11.09 на артефактах прогона A (`~/tm-coldrun-a/evidence/spread.json`, 69 записей; контроль печатает сам прибор: «terms rendered at all: 40, control: terms considered 69»): у **29** термов `renderings={}`, и для **26 из 29** ФИНАЛЬНАЯ форма банка РЕАЛЬНО стоит в отгруженном тексте — `三转` «третий оборот» · `三转蛊师` · `丫头片子` · `五更天` · `仙师` · `侧室` · `十大奇蛊` · `古月一族` · `唐诗宋词` · `四更时` · `宗族祠堂` · `宗祖祠堂` · `开窍` · `怀璧之罪` · `方之一脉` · `方家` · `更夫` · `梆子` · `正派` · `白家寨` · `老嬷嬷` · `话事人` · `邪魔` · `雪盐` · `魔道` · `魔道巨擘`. ⇒ **`spread=0` у них значит «передачи НЕ НАШЁЛ», а читается как «форма одна»**, и итоговая строка «TERMS SHIPPED IN MORE THAN ONE SHAPE: 0» посчитана по 40 термам, а не по 69. ⚠ Матчер ловит СЛОВО, а не форму: у `高脚吊楼` он вернул «Свайные», тогда как текст несёт «свайного дома / свайные дома / свайных домов». ⛔ Это приоритет №1 владельца и ЕДИНСТВЕННЫЙ прибор, который его меряет; сегодня он отвечает за 58 % книги, а отчитывается за 100 %. Носитель разбора — эррата 11.09-з | бэкенд | **скоро** | знаменатель печатается ВСЕГДА («нашёл у M из N»), ненайденные проверяются текстом, а не засчитываются в консистентные; матчер сверяется формой, а не словом | приёмка прогона A, пере-снято 11.09 | -| 435 | **ЭСКАЛАЦИЯ НЕ МОЖЕТ ИСПОЛНИТЬСЯ НИ НА ОДНОМ БОЕВОМ КОНФИГЕ — построена, ратифицирована и выключена данными.** `backend/configs/pipeline-c1.yaml:241`=`budget_usd: 0` (⚠ испр. 17.09: было :223; в файле ДВА вхождения токена, цель — та, над которой стоит комментарий «budget_usd=0 ⇒ эскалация НЕ исполняется», а не упоминание внутри разбора другого конфига), и комментарий строкой выше говорит прямо: «budget_usd=0 ⇒ эскалация НЕ исполняется (НИ chains, НИ stage.escalate_to)… **Приёмочная сессия 蛊真人 ОБЯЗАНА выставить budget_usd>0**, иначе echo-эскалация черновика (D18) не выстрелит. Дефолт 0 держит CI/Ф0 зелёными без gemini/mistral-ключей». ⇒ дефолт выбран под ЗЕЛЕНЬ CI, а не под продукт, и требует ручного оверрайда, которого не сделал ни прогон A (его §10 п.2 честно пишет «эскалация не исполнялась ни разу»), ни прогон B (решение оркестратора 11.09: НЕ трогать, чтобы сохранить байт-в-байт тождество покупающего файла A↔B — сравнимость денег дороже одного непроверенного пути). ⛔ Значит путь эскалации не исполнялся живьём ДВА прогона подряд, и его первое живое исполнение стоит отдельного дешёвого замера, а не контаминации сквозного прогона. ⚠ Класс тот же, что у ряда 433: **механизм лендится выключенным, и выключенность живёт в ДАННЫХ, где её не видит ни один гейт** ⚠ **16.09 (`D39.254` п.2):** владелец назвал фоллбек на другую модель ОЖИДАЕМЫМ механизмом банка. ⇒ `budget_usd: 0` перестал быть безобидным умолчанием. ⛔ **ИСПР. 16.09, СВЕРЕНО ДЕРЕВОМ: включение бюджета банк-ролям НЕ ПОМОЖЕТ, а заденет черновик.** У внутренних вызовов хоп нулевой НАМЕРЕННО — `backend/internal/config/internal_call.go:80`=`no escalation hop` («maybeEscalate is reached from runStage, not from the internal-call paths, and these calls degrade by leaving their work unchanged rather than by paying a second model»); сам `maybeEscalate` выходит на пустом хопе (`backend/internal/pipeline/escalation.go:125`=`st.ResolvedHop == ""`), а банк-роль зовёт попытку напрямую, мимо `runStage`. Все ТРИ боевых `escalate_to` стоят у стадии `draft` (`backend/configs/pipeline-c1.yaml:91`=`escalate_to: deepseek-v4-pro`, а также arm-glm:42 и arm-mistral:46) ⇒ `budget_usd>0` включает эхо-эскалацию ЧЕРНОВИКА (D18) и только её. **Фоллбеку банка нужны три отдельные вещи:** свой хоп во внутреннем вызове (это смена ратифицированного поведения шва, не настройка), свой бюджет либо явно названное разделение общего пула (`escalation.go:91-99` читает ОДИН пул на книгу), и вызов через петлю, а не через `runAttempt`. Нашёл советчик-фабл, проверено деревом оркестратором.| бэкенд | скоро | адресный $0.03-замер пути эскалации отдельным прогоном ЛИБО решение владельца о боевом дефолте | прогон B, пре-рег 11.09 | +| 435 | **ЭСКАЛАЦИЯ НЕ МОЖЕТ ИСПОЛНИТЬСЯ НИ НА ОДНОМ БОЕВОМ КОНФИГЕ — построена, ратифицирована и выключена данными.** `backend/configs/pipeline-c1.yaml:243`=`budget_usd: 0` (⚠ испр. 17.09: было :223; в файле ДВА вхождения токена, цель — та, над которой стоит комментарий «budget_usd=0 ⇒ эскалация НЕ исполняется», а не упоминание внутри разбора другого конфига), и комментарий строкой выше говорит прямо: «budget_usd=0 ⇒ эскалация НЕ исполняется (НИ chains, НИ stage.escalate_to)… **Приёмочная сессия 蛊真人 ОБЯЗАНА выставить budget_usd>0**, иначе echo-эскалация черновика (D18) не выстрелит. Дефолт 0 держит CI/Ф0 зелёными без gemini/mistral-ключей». ⇒ дефолт выбран под ЗЕЛЕНЬ CI, а не под продукт, и требует ручного оверрайда, которого не сделал ни прогон A (его §10 п.2 честно пишет «эскалация не исполнялась ни разу»), ни прогон B (решение оркестратора 11.09: НЕ трогать, чтобы сохранить байт-в-байт тождество покупающего файла A↔B — сравнимость денег дороже одного непроверенного пути). ⛔ Значит путь эскалации не исполнялся живьём ДВА прогона подряд, и его первое живое исполнение стоит отдельного дешёвого замера, а не контаминации сквозного прогона. ⚠ Класс тот же, что у ряда 433: **механизм лендится выключенным, и выключенность живёт в ДАННЫХ, где её не видит ни один гейт** ⚠ **16.09 (`D39.254` п.2):** владелец назвал фоллбек на другую модель ОЖИДАЕМЫМ механизмом банка. ⇒ `budget_usd: 0` перестал быть безобидным умолчанием. ⛔ **ИСПР. 16.09, СВЕРЕНО ДЕРЕВОМ: включение бюджета банк-ролям НЕ ПОМОЖЕТ, а заденет черновик.** У внутренних вызовов хоп нулевой НАМЕРЕННО — `backend/internal/config/internal_call.go:83`=`no escalation hop` («maybeEscalate is reached from runStage, not from the internal-call paths, and these calls degrade by leaving their work unchanged rather than by paying a second model»); сам `maybeEscalate` выходит на пустом хопе (`backend/internal/pipeline/escalation.go:125`=`st.ResolvedHop == ""`), а банк-роль зовёт попытку напрямую, мимо `runStage`. Все ТРИ боевых `escalate_to` стоят у стадии `draft` (`backend/configs/pipeline-c1.yaml:93`=`escalate_to: deepseek-v4-pro`, а также arm-glm:42 и arm-mistral:46) ⇒ `budget_usd>0` включает эхо-эскалацию ЧЕРНОВИКА (D18) и только её. **Фоллбеку банка нужны три отдельные вещи:** свой хоп во внутреннем вызове (это смена ратифицированного поведения шва, не настройка), свой бюджет либо явно названное разделение общего пула (`escalation.go:91-99` читает ОДИН пул на книгу), и вызов через петлю, а не через `runAttempt`. Нашёл советчик-фабл, проверено деревом оркестратором.| бэкенд | скоро | адресный $0.03-замер пути эскалации отдельным прогоном ЛИБО решение владельца о боевом дефолте | прогон B, пре-рег 11.09 | | 436 | ⛔ **ИМЯ ВЕРДИКТА `split` УТВЕРЖДАЕТ БОЛЬШЕ, ЧЕМ МЕРЯЕТ ЕГО ПРЕДИКАТ — и первым же живым прогоном он оболгал подписанное имя героя.** Предикат (`backend/internal/pipeline/bookconsistency.go`, греп `func (v *verdictAcc) observe`) ставит `split`, когда в главе **попаданий МЕНЬШЕ, чем срабатываний** источника, либо не найдено ни одного. Читающий отчёт видит «термин разъехался», а сказано «нашли не каждое срабатывание» — это РАЗНЫЕ утверждения. ⛔ Замер прогона B: вердикт `split` по `方源` во всех трёх главах, тогда как в отгруженном тексте **58 вхождений в четырёх падежах и НОЛЬ конкурирующих транслитераций** (пере-снято оркестратором; голые «Фан» принадлежат другим термам банка — `方正`, `方之一脉`, `方家`, `方老魔`). ⇒ **самая тревожная строка приоритета №1 оказалась артефактом**, и владельцу её понесли бы как расхождение. ⚠ Родня ряду **434** (прибор не находит передачу у 26 термов из 69): вместе они означают, что **числа консистентности прогона B базовой линией НЕ являются до починки** | бэкенд | **скоро** | вердикт зовётся тем, что утверждает («не каждое срабатывание покрыто»), либо предикат усиливается до настоящего разъезда; падеж не считается второй передачей | прогон B, акт `D39.252` п.3 | | 437 | **САМАЯ КРУПНАЯ ХУДОЖЕСТВЕННАЯ ПОТЕРЯ ПРОГОНА ИЗМЕРИМА ОДНИМ ВЫЧИТАНИЕМ, КОТОРОГО НИКТО НЕ ДЕЛАЕТ.** Замер оркестратора на прогоне B: абзацев в оригинале **233**, в отгруженном переводе **162** — сжатие **−30 %** (контроль: 9021 знак оригинала против 30 283 перевода). Движок печатает `sentences/narrative-paragraph` и знает число абзацев только В ПЕРЕВОДЕ; числа абзацев ИСХОДНИКА у него нет, поэтому порога нет и флага нет. ⚠ Для ранобэ, где абзац — единица ритма и реплики, схлопывание трёх абзацев в один меняет темп сильнее, чем любая лексическая правка, и читатель это чувствует раньше, чем термины. ⇒ дешевле всех прочих приборов качества: две величины и одно деление | бэкенд | скоро | счёт абзацев ИСХОДНИКА рядом со счётом перевода + порог, при котором сжатие флагуется | прогон B, акт `D39.252` п.5 | -| 438 | ⛔ **БАНК-РОЛИ ИДУТ МИМО ОБЕИХ ВЕТВЕЙ ЛЕЧЕНИЯ: у черновой стадии лекарство есть, у терминолога нет ни лекарства, ни счётчика.** Обе ветви живут в цикле `runStage` (`backend/internal/pipeline/stagerun.go`, греп `regenerating with less thinking` и `regenerating with a larger budget`), а `terminologist.go` (греп `return r.runAttempt`) зовёт попытку НАПРЯМУЮ. ⛔ Замер прогона B: на попытке 1 классификатор дал `asked=22 answered=4` (`length`, $0.012646) и `asked=24 answered=0` (`empty`, $0.012133) — **42 терма из 66 без машинного типа, оба провальных батча ОПЛАЧЕНЫ, регенерации не было**; у черновой стадии та же мина вылечена 5 раз из 5. ⚠ **Это СТОХАСТИКА, а не регрессия** (сказала сама зона): на резюме тот же классификатор ответил 22/22 · 19/19 · 24/24, у прогона A все три батча чисты. ⚠ И вторая половина — НАБЛЮДАЕМОСТЬ: итоговая строка печатает `classify_batches_dropped=0 unanswered=0`, и это не ложь, а ОТСУТСТВИЕ — счётчик считает батчи, выброшенные БЮДЖЕТОМ (комментарий `terminologist.go` сам предупреждает, что «unanswered читается как вердикт о ТЕРМАХ, когда он отчасти вердикт о ДЕНЬГАХ»), а счётчика доли ОТВЕТОВ нет ни одного; единственный носитель факта — WARN посреди прохода ⚠ **16.09 (`D39.254` п.2):** владелец ожидает у банк-ролей ретрай и отдельный переспрос как штатный механизм, а не как улучшение. Предмет входит в первый банк-пак вместе с N-1. ⛔ **ДОБАВКА 16.09, СВЕРЕНО ДЕРЕВОМ — у петли регенерации есть денежная мина, и её надо заказать вместе с петлёй:** тождество запроса включает индекс попытки и `maxTokens` (`backend/internal/pipeline/stagerun.go:428`=`attemptRequest is the ONE definition` (⚠ испр. 17.09: было :485)), а проба «уже оплачено» у банк-батча спрашивает ТОЛЬКО попытку 0 с базовым бюджетом (`backend/internal/pipeline/terminologist.go:899`=`paidAfterBurns(st, st.Model` (⚠ испр. 17.09: было :840)). ⇒ попытка с другим бюджетом пробе НЕВИДИМА, и доккомментарий рядом сам называет исход: ложное «оплачено» пропускает покупку мимо ролевого суб-бюджета, «under nothing but the book ceiling». **Петля обязана расширить пробу на лестницу попыток (attempt × maxTokens), иначе кап пожизненного пула на повторы не действует.** Нашёл советчик-фабл, проверено деревом оркестратором.| бэкенд | **скоро** | банк-роль получает ту же ветвь регенерации, что черновая стадия, ПЛЮС счётчик доли ответов в итоговой строке | прогон B, акт `D39.252` п.9 | +| 438 | ⛔ **БАНК-РОЛИ ИДУТ МИМО ОБЕИХ ВЕТВЕЙ ЛЕЧЕНИЯ: у черновой стадии лекарство есть, у терминолога нет ни лекарства, ни счётчика.** Обе ветви живут в цикле `runStage` (`backend/internal/pipeline/stagerun.go`, греп `regenerating with less thinking` и `regenerating with a larger budget`), а `terminologist.go` (греп `return r.runAttempt`) зовёт попытку НАПРЯМУЮ. ⛔ Замер прогона B: на попытке 1 классификатор дал `asked=22 answered=4` (`length`, $0.012646) и `asked=24 answered=0` (`empty`, $0.012133) — **42 терма из 66 без машинного типа, оба провальных батча ОПЛАЧЕНЫ, регенерации не было**; у черновой стадии та же мина вылечена 5 раз из 5. ⚠ **Это СТОХАСТИКА, а не регрессия** (сказала сама зона): на резюме тот же классификатор ответил 22/22 · 19/19 · 24/24, у прогона A все три батча чисты. ⚠ И вторая половина — НАБЛЮДАЕМОСТЬ: итоговая строка печатает `classify_batches_dropped=0 unanswered=0`, и это не ложь, а ОТСУТСТВИЕ — счётчик считает батчи, выброшенные БЮДЖЕТОМ (комментарий `terminologist.go` сам предупреждает, что «unanswered читается как вердикт о ТЕРМАХ, когда он отчасти вердикт о ДЕНЬГАХ»), а счётчика доли ОТВЕТОВ нет ни одного; единственный носитель факта — WARN посреди прохода ⚠ **16.09 (`D39.254` п.2):** владелец ожидает у банк-ролей ретрай и отдельный переспрос как штатный механизм, а не как улучшение. Предмет входит в первый банк-пак вместе с N-1. ⛔ **ДОБАВКА 16.09, СВЕРЕНО ДЕРЕВОМ — у петли регенерации есть денежная мина, и её надо заказать вместе с петлёй:** тождество запроса включает индекс попытки и `maxTokens` (`backend/internal/pipeline/stagerun.go:428`=`attemptRequest is the ONE definition` (⚠ испр. 17.09: было :485)), а проба «уже оплачено» у банк-батча спрашивает ТОЛЬКО попытку 0 с базовым бюджетом (`backend/internal/pipeline/terminologist.go:1026`=`paidAfterBurns(st, st.Model` (⚠ испр. 17.09: было :840)). ⇒ попытка с другим бюджетом пробе НЕВИДИМА, и доккомментарий рядом сам называет исход: ложное «оплачено» пропускает покупку мимо ролевого суб-бюджета, «under nothing but the book ceiling». **Петля обязана расширить пробу на лестницу попыток (attempt × maxTokens), иначе кап пожизненного пула на повторы не действует.** Нашёл советчик-фабл, проверено деревом оркестратором.| бэкенд | **скоро** | банк-роль получает ту же ветвь регенерации, что черновая стадия, ПЛЮС счётчик доли ответов в итоговой строке | прогон B, акт `D39.252` п.9 | | 439 | ⛔⛔ **БАНК КНИГИ НЕДЕТЕРМИНИРОВАН ПО ПОСТРОЕНИЮ: он есть функция ЧЕРНОВИКА, а черновик — стохастический выход модели.** Замер сессии прогона B, пере-снятый оркестратором СВОИМ запросом и сошедшийся дословно: `retrieval_state.banknote_detail` двух прогонов на ОДНИХ И ТЕХ ЖЕ шести чанках, побайтно один исходник (sha среза сверена) и тождественный покупающий конфиг (sha `pipeline-c1.yaml` совпал) — предложений **A 98 · B 93 · общих 74 ⇒ ЖАККАР 0.63**. ⛔ **Расходится не только СОСТАВ, но и ГРАНУЛЯРНОСТЬ ключа:** на `ch3/1` прогон A предлагает СОСТАВНЫЕ (`丙等资质` · `族长家老` · `舅父舅母`), а B — их СОСТАВЛЯЮЩИЕ (`丙等` · `资质` · `族长` · `家老` · `舅母` · `舅父`); на `ch2/0` предложение B — строгое ПОДМНОЖЕСТВО A, беднее на восемь. Отсюда же исчезновение `舅父舅母`, которое встречается в исходнике **14 раз** и есть в банке A при отсутствии в B — частотным порогом это не объясняется. ⛔ **СЛЕДСТВИЕ СТАРШЕ РЯДА 436: консистентность мерится ПО СТРОКАМ БАНКА, а строки между прогонами разные ⇒ у `I1`/`I2` двух прогонов РАЗНЫЕ ЗНАМЕНАТЕЛИ, и они несравнимы не потому, что прибор плох, а по построению.** ⚠ И это прямо задевает цель 6 («воспроизводимый прогон — повторение без сюрпризов»): снапшот и голден стерегут ВХОД, а состав банка в них не заперт. ⚠ Границы замера названы сессией: одна книга, три главы, шесть чанков, ОДНА пара прогонов — установлен РОД расхождения (состав + гранулярность), не его обычная величина; как из предложений собирается финальный банк, не читал никто ⛔ **ПОСЫЛКА «ТОЖДЕСТВЕННЫЕ ВХОДЫ» НЕВЕРНА, снято 12.09 опровергателем и пере-проверено оркестратором.** Совпадение sha `pipeline-c1.yaml` было выдано за тождество входов: `diff -rq` двух фриз-деревьев даёт **52 расходящихся пути** (`chunkrun.go`, `stagerun.go`, `waverun.go`, `disposition.go`, `quality.go`, стеммер), и снапшоты РАЗНЫЕ (`cfd53cc0…` против `fef36e1d…`). ⚠ **Что при этом устояло и держит вывод:** `internal/miner` и `internal/terminology` между фризами **побайтно идентичны** (0 различий), langpack идентичен, `bankParseVersion` совпал, диф `models.yaml` — только комментарии. ⇒ **детерминированная половина не двигалась, двигалась ЧЕРНОВАЯ сторона — а она и производит банкноты.** ⛔ Но ДОЛЯ расхождения, приходящаяся именно на температуру, ЭТОЙ парой прогонов не измерена и измерима быть не может: нужен повтор на ОДНОМ движке, и такого прогона нет. ⚠ И метод числа назвать обязательно: 0.63 — это сумма ПОЧАНКОВЫХ пересечений (74 из 98+93−74); книго-уровневые множества дают 53 из 82 = **0.65**. Вывод переживает оба, число без метода — нет | бэкенд | **скоро** | состав банка воспроизводим при повторе прогона ЛИБО названо и ратифицировано, что банк стохастичен, и тогда числа консистентности сравниваются только ВНУТРИ прогона | прогон B, дописка 12.09 | | 440 | ⛔ **МАЙНЕР ОТСЕКАЕТ ЦЕНТРАЛЬНЫЕ ТЕРМИНЫ КНИГИ ПО ПОСТРОЕНИЮ, А НЕ ПО ПОРОГУ — и это несовпадение ДВУХ РАЗНЫХ ВОПРОСОВ.** Формулировка сессии прогона B, принята дословно: **контраст спрашивает «характерно ли слово для ЭТОГО текста на фоне китайского вообще», а продукт спрашивает «нужна ли слову ОДНА закреплённая передача на всю книгу».** Для `家族` ответ на первый — НЕТ, на второй — ДА. Замер (контроль напечатан: словарь-контраст jieba 0.42.1, **349 046 строк**): `家族` · `族` · `炼制` · `楼阁` · `先机` · `老妈子` — **ЕСТЬ в словаре-контрасте и потому НЕТ в банке ни одного из двух прогонов**, тогда как `方源` · `古月山寨` · `丫头片子` · `怀璧之罪` в словаре отсутствуют и в банк попали. ⇒ **шесть из восьми терминов, на которых читатель поймал разнобой, отсечены ПОТОМУ ЧТО ОНИ ОБЫЧНЫЕ КИТАЙСКИЕ СЛОВА.** ⛔ Цена названа текстом: `族` встречается в срезе **29 раз**, `家族` — **9**, и «род ↔ клан» есть КРУПНЕЙШАЯ находка приоритета №1 за оба прогона. ⚠ Лечится в ПОЛНОТЕ МАЙНИНГА, а не в гейте: энфорсер не молчал — ему не о чем было говорить ⛔⛔ **ПРИЧИННОСТЬ ЭТОГО РЯДА ОПРОВЕРГНУТА 12.09 ЧТЕНИЕМ КОДА — механизм НЕ контраст.** `backend/internal/miner/miner_emit.go`, функция `emissionEligible`: **первым** стоит `if !hasAnyType(c.Types, "name", "place", "title") { return false }`, **вторым** — `if c.Freq < emitMinFreq \|\| subsumed[c.Src] \|\| runeLen(c.Src) < 2`. ⇒ **`族` отсечён БЕЗУСЛОВНО как ОДНОРУННЫЙ**, к контрасту это отношения не имеет; **`家族` отсечён ТИПОМ** — у него 2 руны и freq 9 при `emitMinFreq` 5, то есть он проходит всё, на что ряд указывал, и падает на том, о чём ряд молчал. ⭐ **И настоящая находка ШИРЕ прежней: детерминированный канал по построению эмитирует ТОЛЬКО `name\|place\|title`.** Обычное существительное, несущее в книге (`家族` «род/клан», `炼制` «выплавить»), не может войти в банк этим каналом НИКОГДА — сколько бы раз оно ни встретилось. Это же объясняет, почему строк с провенансом `mined`-без-банкноты **ноль в обоих прогонах**: тип-фильтр так узок, что всё им пропущенное черновик называет и так. ⚠ Прежняя формулировка («ЕСТЬ в словаре-контрасте и ПОТОМУ НЕТ в банке») выдавала корреляцию 6 из 8 за механизм — класс назван и в `CLAUDE.md`. Нашёл опровергатель промта, пере-проверено оркестратором чтением функции | бэкенд | **скоро** | решение владельца: имеет ли право обычное существительное входить в банк детерминированным каналом, и если да — каким признаком, кроме типа | прогон B, §18.1(а) + дописка 12.09 | | 442 | Комментарий `backend/internal/pipeline/volume.go:341`=`are then pinned to a superseded one` обещает «stops loudly», а без `--resnapshot`, пока в книге есть новые юниты, покупка проходит без ошибки (исполнено на $0-стабе) | бэкенд | когда-нибудь | правка комментария под поведение | `research/35`, K1-3 | | 443 | Устаревшие комментарии банкового контура: `miner_emit.go:224-227`, `terminologist.go:33`, справка `--verify-bank`, `mining.go:212-213`, `memory.go:819-822`, заголовок `injection.txt:6` про снятую пометку ⟨проверить⟩ | бэкенд | когда-нибудь | сверка комментариев с поведением | `research/35` Б-3 | -| 444 | **Ложная атрибуция в коде:** `backend/internal/membank/memory.go:947`=`AVOID gender-marking constructions until the reveal` пишет «a masculine default when unavoidable, D19.3», а в теле D19 п.3(в) этого нет; D5 п.1 говорит обратное — «не дефолтить в мужской». ⚠ `internal/terminology/classify.go:43`=`which is a decision about a book` НЕ чинить: там D19.3 пересказан верно. Едет вместе с нотой о том, что делать при невозможной безродовой форме ⚠ **16.09 (`D39.254` п.3):** владелец решил, что делать при невозможной безродовой форме — перестроить фразу, а если литературно не выходит, писать как лучше читается. ⇒ правится и текст данных `injection.txt:12`, не только атрибуция.| бэкенд | скоро | правка атрибуции после ноты | `research/35` Б-4, G-1 | +| 444 | **Ложная атрибуция в коде:** `backend/internal/membank/memory.go:947`=`AVOID gender-marking constructions until the reveal` пишет «a masculine default when unavoidable, D19.3», а в теле D19 п.3(в) этого нет; D5 п.1 говорит обратное — «не дефолтить в мужской». ⚠ `backend/internal/terminology/classify.go:43`=`which is a decision about a book` НЕ чинить: там D19.3 пересказан верно. Едет вместе с нотой о том, что делать при невозможной безродовой форме ⚠ **16.09 (`D39.254` п.3):** владелец решил, что делать при невозможной безродовой форме — перестроить фразу, а если литературно не выходит, писать как лучше читается. ⇒ правится и текст данных `injection.txt:12`, не только атрибуция.| бэкенд | скоро | правка атрибуции после ноты | `research/35` Б-4, G-1 | | 445 | ⚠ **ПОЛОВИНА ЗАКРЫТА актом `D39.257`:** мусор (`dst` без букв ВООБЩЕ) больше не едет законом — он падает в `Unanswered`, стережётся пином и мутацией. **ОСТАТОК — отказ ПРОЗОЙ:** механизм построен и инертен до первой фразы в реестре, то есть ряд закрывается вместе со строкой о заполнении реестра. Ниже — исходная формулировка. **Отказ терминолога прозой становится передачей и едет редактору законом.** Неотвеченными считать и `dst` без букв, и отказную фразу (`家族 → «не термин»`, `族长 → «90»` — исполнено). ⚠ Не гигиена, а поведенческая правка на денежном пути: меняет содержимое банка, а с ним `memory_version` и пере-редактуру под согласием. Популяция на A/B нулевая (0 из 69 и 0 из 66 при контроле 69/69 и 66/66), на длинной книге у бюджетного потолка — нет | бэкенд | скоро | разбор ответа роли + пин; решение владельца по В2 | `research/35` Б-5, П3 | | 446 | **Свёртки написания исходника — из ядра в данные языка, ЦЕЛИКОМ.** `trad2simp` плюс арифметика каны, схема замен целевой орфографии вместо литерала ё→е (ряд 14). Правило «пустой реестр — инертный no-op», образцы построены (`family-morphology.txt`, `stemmer.go`). ⚠ Цена одна в любой плоскости: версия свёрток входит в `NormVersion`, а он — в тег нарезки и ключ манифеста ⇒ только в окне перекроя глав | бэкенд | когда-нибудь (окно перекроя, ряд 161) | вынос данных + пере-снапшот | `research/35` Б-6, П8 | | 447 | Подписанный `古月山寨` во втором проходе снова спрашивается у терминолога и оплачивается: вид держит слово владельца, счёт — нет | бэкенд | скоро | фильтр подписанных до платного вызова | `research/35` Б-7, K1 | @@ -366,11 +366,11 @@ | 454 | **Ложная атрибуция ноты в комментарии кода:** `backend/internal/pipeline/quality.go:51`=`Echo is SPLIT by stage` — «Split echo by stage (D39.18 owner decision)», а в теле `D39.18` расщепления по стадиям нет вовсе (пере-снято: «split» 0, «стади» 0); носитель решения — `D39.19` п.4, где стоит `echo_draft_rate`. Пред-существует на HEAD, паком не заведено; форма «D39.18-follow-up» на `:404` корректна и правки не требует. Тот же класс, что чинил круг 8 у четырёх других носителей | бэкенд | когда-нибудь | правка комментария | `D39.255`, приёмка пака 291 | | 455 | ⛔ **ТРИ ОПУБЛИКОВАННЫХ КЛЮЧА КАЧЕСТВА СМЕНИЛИ СМЫСЛ ОДНИМ ПАКОМ, а его остаток называл два.** (а) `ProcessedUnits` / `processed_units` — знаменатель strip-rate теперь включает позиции со стоп-меткой, то есть юниты, не дошедшие до финальной стадии; код сам говорит «„REACHED THE FINAL STAGE“ … too strong now». (б) `EchoDraftRecovered` / `echo_draft_recovered` — числитель СУЖЕН условием `shippedText`; доккомментарий признаёт «measured before this change reads HIGHER … the two are not comparable across it». (в) эдит-числитель — снят гейт `DispFlagged` (ратифицировано `D39.255` как эррата к `D39.19` п.4). ⇒ нужен перечень «до / после» у каждого ключа и пин несопоставимости, иначе сравнение прогонов через эту границу молча врёт | бэкенд | скоро | перечень в носителе + пин | `D39.255`, приёмка пака 291 | | 456 | **Пин читательской фразы отчитывается за КЛАСС, а меряет СРЕЗ.** `backend/internal/pipeline/readerholewords_test.go:47-64`=`DroppedReason: string(FlagHardRefusal)`: строки таблицы варьируют причину флага (`retry_unaffordable`, `cancelled`, `hard_refusal`, `sanitizer_defect`), но `DroppedReason` захардкожен `FlagHardRefusal` во ВСЕХ строках. Поэтому строка «a stop mark over a unit that lost a member for good» меряет защитимый случай — член потерян настоящим отказом — и молчит ровно о случае ряда 375, где выпавший член САМ есть метка стопа. Прогон: 5/5 PASS, то есть зелень ничего не говорит о предмете | бэкенд | скоро | варьировать `DroppedReason` по строкам | `D39.255`, приёмка пака 291 | -| 457 | **ТРИ ПРОТУХШИХ ЯКОРЯ В ДОКАХ ФРОНТ-ЗОНЫ, и две цели живы по известным адресам.** `frontend/docs/frontend-PROGRESS.md:187`=`Какое слово о состоянии книги стоит в дереве` целит в контракт по адресу 1054 — токен живёт на `docs/architecture/14-api-contract/README.md:1213`=`не различает две беды` (⚠ испр. 17.09: было :1138); `frontend/docs/frontend-PROGRESS.md:190`=`Фразы отказа книги` целит в openapi по адресу 1606 — enum отказов живёт на `docs/architecture/14-api-contract/openapi.yaml:1679`=`enum: [source_unreadable, not_configured, processing_failed, content_refused]` (⚠ испр. 17.09: было :1633); `frontend/docs/STACK_DECISIONS.md:263`=`pend.Source = u.sourceText()` целит в экспорт по адресу 176 — присваивание живёт на `backend/internal/pipeline/export.go:178`=`pend.Source = u.sourceText()` (замер 16.09: `sourceText()` в файле два, второе — `ce.Source` на 344, и оно про другое). ⛔ **Мёртвые адреса здесь НАЗВАНЫ СЛОВАМИ, а не якорями, и это существенно:** выписав их в форме `` `путь:строка`=`токен` ``, я воспроизвёл чужую поломку у себя — линтер прочитал их как МОИ живые якоря и дал три новых красных (8 → 11). **Документируя протухший якорь, не пиши его якорем.** ⚠ Правит их ФРОНТ: доки чужой зоны оркестратор не переписывает, а обе уехавшие цели — В МОЕЙ зоне, поэтому адреса названы здесь готовыми. ⛔ Замер 16.09: цели контракта БАЙТ-ИДЕНТИЧНЫ дереву и HEAD (README 1608 строк в обеих, `openapi.yaml` 3497 в обеих) ⇒ якоря протухли НЕ лендингом приёмки, а раньше. ⚠ И они едва не уехали в находку: контрольный прогон на HEAD показал 25 строк из 27 — линтер капит список, и «эти два якоря новые» было артефактом прибора, снятым замером | фронт | когда-нибудь | три якоря зелёные в `python3 docs/scripts/counts.py --lint` | приёмка пака «КУПЛЕНО — ЗНАЧИТ ДОСТАВЛЕНО» 16.09 (`D39.255`) | +| 457 | **ТРИ ПРОТУХШИХ ЯКОРЯ В ДОКАХ ФРОНТ-ЗОНЫ, и две цели живы по известным адресам.** `frontend/docs/frontend-PROGRESS.md:187`=`Какое слово о состоянии книги стоит в дереве` целит в контракт по адресу 1054 — токен живёт на `docs/architecture/14-api-contract/README.md:1282`=`не различает две беды` (⚠ испр. 17.09: было :1138); `frontend/docs/frontend-PROGRESS.md:190`=`Фразы отказа книги` целит в openapi по адресу 1606 — enum отказов живёт на `docs/architecture/14-api-contract/openapi.yaml:1679`=`enum: [source_unreadable, not_configured, processing_failed, content_refused]` (⚠ испр. 17.09: было :1633); `frontend/docs/STACK_DECISIONS.md:263`=`pend.Source = u.sourceText()` целит в экспорт по адресу 176 — присваивание живёт на `backend/internal/pipeline/export.go:178`=`pend.Source = u.sourceText()` (замер 16.09: `sourceText()` в файле два, второе — `ce.Source` на 344, и оно про другое). ⛔ **Мёртвые адреса здесь НАЗВАНЫ СЛОВАМИ, а не якорями, и это существенно:** выписав их в форме `` `путь:строка`=`токен` ``, я воспроизвёл чужую поломку у себя — линтер прочитал их как МОИ живые якоря и дал три новых красных (8 → 11). **Документируя протухший якорь, не пиши его якорем.** ⚠ Правит их ФРОНТ: доки чужой зоны оркестратор не переписывает, а обе уехавшие цели — В МОЕЙ зоне, поэтому адреса названы здесь готовыми. ⛔ Замер 16.09: цели контракта БАЙТ-ИДЕНТИЧНЫ дереву и HEAD (README 1608 строк в обеих, `openapi.yaml` 3497 в обеих) ⇒ якоря протухли НЕ лендингом приёмки, а раньше. ⚠ И они едва не уехали в находку: контрольный прогон на HEAD показал 25 строк из 27 — линтер капит список, и «эти два якоря новые» было артефактом прибора, снятым замером | фронт | когда-нибудь | три якоря зелёные в `python3 docs/scripts/counts.py --lint` | приёмка пака «КУПЛЕНО — ЗНАЧИТ ДОСТАВЛЕНО» 16.09 (`D39.255`) | | 458 | **ПЯТНАДЦАТЬ ГОЛЫХ ЯКОРЕЙ В ЖИВЫХ СТРОКАХ: путь и номер есть, ТОКЕНА ОЖИДАНИЯ нет — линтер такой якорь не читает, и «ноль жалоб» тут неотличимо от «не разобран».** Одиннадцать в `docs/BACKLOG.md` — pipeline/export.go 307 · stagerun.go 93 · seed/seed.go 24 · store/chunkstatus.go 92 · bankmaterialize.go 214 и 295 · export.go 174 и 320–322 · quality.go 492 · status.go 538–543 · voicerun.go 46 (⚠ у восьми нет и КОРНЯ пути, а такой якорь не ловится даже существованием файла); четыре в `docs/experiments/00-provider-quirks.md` — pipeline-c1.yaml 129 · pipeline-arm-glm.yaml 61 · pipeline-arm-deepseek-pro.yaml 62 · pipeline-arm-mistral.yaml 61. ⛔ **Адреса здесь намеренно НЕ в форме якоря:** выписав их якорями, я за одну смену ДВАЖДЫ завёл своими руками ровно тот дефект, который ряд описывает — сперва в ряду 457 с чужими протухшими целями, потом здесь, и оба раза поймал ХУК, а не я. **Перечень поломанных якорей сам якорями не пишется.** ⛔ **Чинить ОПТОМ нельзя:** токен, подобранный под то, что в цели ОКАЗАЛОСЬ, есть подгонка под зелень (`D39.121`) — каждый разбирается чтением прозы, которая его описывает, и половина таких разборов кончается тем, что уехала ЦЕЛЬ, а не номер. Замер 16.09 (`D39.255` п.10): пред-существуют — лендинг приёмки эти строки лишь дополнял, а ввёл он двенадцать своих, и они закрыты в тот же заход | оркестратор | когда-нибудь | у каждого якоря есть корень пути и токен; пред-коммитный хук на этих строках молчит | приёмка пака «КУПЛЕНО — ЗНАЧИТ ДОСТАВЛЕНО» 16.09 (`D39.255`) | -| 459 | **РАТИФИЦИРОВАННАЯ НОТА И ДЕРЕВО РАСХОДЯТСЯ ПО ОТКАЗ-СИГНАЛУ ⟦TM-NO-DST⟧, и банковый пак упрётся в это на первой же строке.** `D39.102` п.2 числит отказ-сигнал в корзине «закрыть по нужности», ратифицированной ЦЕЛИКОМ; п.3 той же ноты добавляет его в «опровергнуто/не заводится»: «NoDst-почти-сентинел на zh-ru (target_script обязателен конфигом, OffLanguage отбивает)». ⛔ **В ДЕРЕВЕ он жив и стоит на БОЕВОМ проводе zh-ru:** `backend/prompts/zh-ru/terminologist.md:36`=`не можешь выбрать перевод уверенно` велит роли вернуть сентинел и называет это нормальным исходом; парсер ждёт его вместе с искажёнными формами (`backend/internal/terminology/terminology.go:694`=`const NoDst = "⟦TM-NO-DST⟧"`, `backend/internal/terminology/terminology.go:1248`=`func isNoDst`); счёт печатается прогоном (`backend/internal/pipeline/terminologist.go:702`=`"declined", res.Declined` (⚠ испр. 17.09: было :649)). Итог консилиума повторил НОТУ, а не дерево (`docs/research/35-bank-memory-consilium.md` §П3, «исхода движка „это не термин“ нет и не вводится»). ⇒ пак обязан выбрать ЯВНО: сентинел остаётся законным исходом (тогда ряд 445 — ужесточение разбора ответа) либо снимается из промта — а это двигает хеш запроса и перекупает проход на консолидированных книгах. Найдено советчиком-фаблом, проверено деревом оркестратором | бэкенд | скоро | нота и дерево говорят одно, выбор назван нотой | совет фабла 16.09 + сверка дерева оркестратором | +| 459 | **РАТИФИЦИРОВАННАЯ НОТА И ДЕРЕВО РАСХОДЯТСЯ ПО ОТКАЗ-СИГНАЛУ ⟦TM-NO-DST⟧, и банковый пак упрётся в это на первой же строке.** `D39.102` п.2 числит отказ-сигнал в корзине «закрыть по нужности», ратифицированной ЦЕЛИКОМ; п.3 той же ноты добавляет его в «опровергнуто/не заводится»: «NoDst-почти-сентинел на zh-ru (target_script обязателен конфигом, OffLanguage отбивает)». ⛔ **В ДЕРЕВЕ он жив и стоит на БОЕВОМ проводе zh-ru:** `backend/prompts/zh-ru/terminologist.md:32`=`не можешь выбрать перевод уверенно` велит роли вернуть сентинел и называет это нормальным исходом; парсер ждёт его вместе с искажёнными формами (`backend/internal/terminology/terminology.go:694`=`const NoDst = "⟦TM-NO-DST⟧"`, `backend/internal/terminology/terminology.go:1248`=`func isNoDst`); счёт печатается прогоном (`backend/internal/pipeline/terminologist.go:806`=`"declined", res.Declined` (⚠ испр. 17.09: было :649)). Итог консилиума повторил НОТУ, а не дерево (`docs/research/35-bank-memory-consilium.md` §П3, «исхода движка „это не термин“ нет и не вводится»). ⇒ пак обязан выбрать ЯВНО: сентинел остаётся законным исходом (тогда ряд 445 — ужесточение разбора ответа) либо снимается из промта — а это двигает хеш запроса и перекупает проход на консолидированных книгах. Найдено советчиком-фаблом, проверено деревом оркестратором | бэкенд | скоро | нота и дерево говорят одно, выбор назван нотой | совет фабла 16.09 + сверка дерева оркестратором | | 461 | **ПЕРЕНОС БАНКА В КНИГУ-ПРОДОЛЖЕНИЕ — СТРОЙКА ПО РЕШЕНИЮ ВЛАДЕЛЬЦА `D39.256`.** Переезжают ДВА слоя: подписанное владельцем и решённое движком. ⛔ Сегодня механизма нет ВООБЩЕ: ни один из 17 не-тестовых файлов `platform/internal/books` и `httpapi` не упоминает ни сид, ни глоссарий, ни дельту, а продолжение приходит ОТДЕЛЬНОЙ книгой. Работа двухзонная: **платформа** — предложить перенос при заведении продолжения и провести выбранные слои; **движок** — форма переносимого (что именно едет: `src`/`sense`/`dst`/`gender`/`status`, и что делать с окнами `since_ch`/`until_ch`, которые нумерованы главами ДРУГОЙ книги). ⚠ Денежная сторона: перенос сокращает пожизненный пул банк-ролей тома 2 ($1+$1), а ошибочно перенесённая строка живёт во всей следующей книге — значит перенос обязан быть видимым и отменяемым, а не молчаливым. ⚠ Это первый предмет, за который платформе есть что заказать: её собственный major `PD-441` закрыт с её стороны, остальное — minor и info | платформа + бэкенд | скоро | книга-продолжение получает банк предшественницы двумя слоями, перенос виден владельцу и отменяем | `D39.256`, слово владельца 16.09 ⛔ **НАЗВАНО НЕЗАВИСИМО ДВУМЯ ИСТОЧНИКАМИ 16.09 (консилиум §1.2 N-1 и сессия пака `D39.257`): «решённое движком» НЕ СУЩЕСТВУЕТ КАК ХРАНИМЫЙ СТАТУС.** Статусов три — `auto`/`draft`/`approved`, а «решено» есть ВЫВОД, который считается на прогоне фильтром `dropBankSettled` из банка плюс черновиков, и предикат привязан к БАЗИСУ конкретной книги: он требует, чтобы отпечаток улик строки совпал с записанным, и чтобы то же было верно для всех членов её юнита. ⚠ У книги-продолжения улики другие по построению ⇒ переносится СОДЕРЖИМОЕ строки, а статус «решено» в новой книге заново НЕ наследуется: унаследованный, он утверждал бы совпадение улик, которого нет. ⇒ развилка стройки: либо переносить вывод вместе с уликами, на которых он сделан, либо заводить статус — и второе есть ратификация, а не оформление. ⚠ И третьего у строки нет вовсе: провенанса — откуда она пришла — нет ни поля, ни места. ⛔ **РАЗВИЛКА, КОТОРУЮ РЕШАТЬ ДО ПРОМТА — МЕТКА ИСТОЧНИКА у перенесённого слоя, и от неё зависит, сэкономит ли перенос хоть доллар (разбор советчика 16.09, адреса пере-сняты).** Как `mined` — строка отвечает «да» предикату `backend/internal/membank/memseed.go:766`=`Source == "mined"`, майнер тома 2 пере-предлагает поверхность, фильтр решённого её settled не видит ⇒ терминолог пере-спрашивает и ПЕРЕ-ПЛАТИТ каждую строку, а авто-банк перепишется первым же прогоном. Как сид владельца — не пере-платится, НО правка сид-ключа с экрана подписи запрещена ⇒ перенесённую ошибку не исправить, что противоречит требованию «видимо и отменяемо» этого же ряда, и слово движка ложится в файл руки владельца против онтологии. ⇒ предложен ТРЕТИЙ источник с меткой «унаследованное», грузимый между сидом и авто-банком. ⚠ И различить происхождение по самой строке НЕЛЬЗЯ: комментарий у того же предиката говорит, что строка mined-дельты владельца и строка авто-банка отвечают одинаково, документа происхождения не несёт ни та ни другая. ⚠ Перенос обязан произойти ДО первого прогона тома 2, иначе двигается базовый снапшот и черновая волна пере-платится. ⚠ И платформа СОБРАТЬ переносимую строку из проекции не может (в ней нет рода, склонения и заметки), а копировать слияние руками платформы значит пере-реализовать закон движка ⇒ нужен $0-глагол экспорта переносимого слоя, и сегодня его нет | -| 462 | **АРМ `unresolved` СЧИТАЕТСЯ ПО ЗНАМЕНАТЕЛЮ, ИЗ КОТОРОГО САМ ВЫЧТЕН — доля выходит бессмысленной, и сегодня это невидимо.** Пост-колл-знаменатель = `preCall − unresolved` (`backend/cmd/tmbankprobe/main.go:324`=`rows the role ANSWERED`), а арм отбирает ровно вычтенные строки (`backend/internal/pipeline/stopcontest.go:78`=`CountUnresolved`). На купленном сырье популяция ноль ⇒ в таблице чувствительности не видно. Показано ИСПОЛНЕНИЕМ (ось приёмки, синтетический лист из двух строк): «unresolved only 1/1 = 100.0%» при двух строках листа. ⚠ Денег сегодня не стоит — платного потребителя у предиката нет вовсе, — но по этой сетке будут выбирать ПОРОГ ЗА ДЕНЬГИ, и до первого такого читателя дефект обязан уйти: либо арм считать к pre-call-знаменателю, либо печатать абсолютом без доли | бэкенд | скоро | доля арма считается по популяции, в которую он входит; пин на синтетике | `D39.257` п.5, ось денег | +| 462 | **АРМ `unresolved` СЧИТАЕТСЯ ПО ЗНАМЕНАТЕЛЮ, ИЗ КОТОРОГО САМ ВЫЧТЕН — доля выходит бессмысленной, и сегодня это невидимо.** Пост-колл-знаменатель = `preCall − unresolved` (`backend/cmd/tmbankprobe/main.go:324`=`rows the role ANSWERED`), а арм отбирает ровно вычтенные строки (`backend/internal/pipeline/stopcontest.go:86`=`o.CountUnresolved && strings.TrimSpace(r.Dst)`). На купленном сырье популяция ноль ⇒ в таблице чувствительности не видно. Показано ИСПОЛНЕНИЕМ (ось приёмки, синтетический лист из двух строк): «unresolved only 1/1 = 100.0%» при двух строках листа. ⚠ Денег сегодня не стоит — платного потребителя у предиката нет вовсе, — но по этой сетке будут выбирать ПОРОГ ЗА ДЕНЬГИ, и до первого такого читателя дефект обязан уйти: либо арм считать к pre-call-знаменателю, либо печатать абсолютом без доли | бэкенд | скоро | доля арма считается по популяции, в которую он входит; пин на синтетике | `D39.257` п.5, ось денег | | 463 | **НОВЫЙ ГАРД ЦЕЛИ ЧУВСТВИТЕЛЕН К РЕГИСТРУ, а его сосед по паку — нет.** Исполнено осью: `target="RU"` ⇒ `HasData=false`, `missing=[glossary_header editor_header]`; `"Ru"` и `"ru "` — то же, тогда как `DeclinePhrasesFor("RU ")` регистр и пробелы СВОРАЧИВАЕТ (`backend/internal/lang/declinephrases.go:92`=`strings.ToLower(strings.TrimSpace(targetLang))`), и это прямо запинено доводом «книга, написанная `RU`, молча остаётся без реестра». ⇒ книга с `target_lang: RU` раньше молча шла без блока, теперь НЕ СТАРТУЕТ вовсе. Живых книг с таким написанием 0 из 48 (контроль: yaml прочитано 180, конфигов книг 48, все `ru`) ⇒ риск будущей пары, не сегодняшний. Лечение — свёртка в `InjectionTextsFor`, одна строка | бэкенд | когда-нибудь | регистр цели сворачивается одинаково гардом и реестром | `D39.257` п.6 | | 464 | **ДОККОММЕНТАРИЙ И ПИН СЧИТАЮТ ЧЕТЫРЕ ДВЕРИ ПРИ ПЯТИ АРМАХ.** `backend/internal/pipeline/injectionpreflight.go:24`=`rows reach a book through` перечисляет четыре (терминолог, сид, мината-дельта, авто-банк), пропуская `gates.banknote`, который в самой функции стоит вторым кейсом; тот же счёт в пине (`backend/internal/pipeline/contourpreflight_test.go:349`=`disjunction over the four doors bank rows come through`) при ПЯТИ подтестах. Заголовок отчёта «арм пять» верен — расходится проза вокруг. ⚠ Класс знакомый: комментарий, несущий ЧИСЛО, протухает молча | бэкенд | когда-нибудь | число в доккомментарии и пине равно числу арм | `D39.257` п.6 | | 465 | **РЕЕСТР ОТКАЗНЫХ ФРАЗ ЗАПОЛНЯЕТСЯ ТОЛЬКО С ИЗМЕРЕННОЙ ПОПУЛЯЦИЕЙ.** Сегодня лендится ПУСТЫМ и запинен пустым (`backend/internal/lang/declinephrases_test.go:22`=`TestTheDeclineRegistryShipsEmpty`), и это решение оркестратора, а не недоделка: цена ошибки несимметрична — ложное срабатывание выбрасывает ОПЛАЧЕННУЮ верную передачу, терм спрашивается заново, а ретрая у банк-ролей нет (ряд 438). Популяция на купленном сырье ноль: строк, похожих на отказ прозой, 0 из 265 (контроль осью). ⚠ Контрольная величина в отчёте названа неверно («23 строки файла» при 26) — пере-снять вместе с заполнением | бэкенд | когда-нибудь | фразы заведены вместе с замером их популяции на сырье; пин пустоты заменён пином состава | `D39.257` п.6, вопрос сессии 1 ⚠ **Этот же критерий закрывает и соседний вопрос — решение автора находки 16.09:** синтетичность пина пост-колл-предиката на конфликтах ОТДЕЛЬНЫМ рядом не заводится. Долг тут один и он здесь; когда придёт материал с ненулевой популяцией (длинная книга у бюджетного потолка — единственный названный кандидат), критерий сработает сам. Второй носитель одного факта — отдельный класс ошибки. | @@ -386,7 +386,7 @@ | 475 | **УЛИКИ ПРОГОНА A НЕЧИТАЕМЫ ДВИЖКОВЫМ СТОРОМ, И НОСИТЕЛЯ ЭТОГО ФАКТА НЕТ НИГДЕ.** База прогона A несёт схему 16 при голове 18: `OpenReadOnly` отказывает, а `Open` МИГРИРУЕТ, то есть уничтожает улику при попытке её прочесть. Свойство архива, а не дефект кода — но следующий, кто захочет реплей, потратит час, чтобы это выяснить, и рискует испортить сырьё | бэкенд | когда-нибудь | способ читать старые прогоны назван носителем; опасность миграции при чтении объявлена рядом с ней | сессия пака D39.257, её §10 | | 476 | **ДЕНЬГИ ВТОРОГО ВЫЗОВА НЕ ПОСЧИТАНЫ:** сетка чувствительности даёт число СТРОК, а не сумму, поэтому «сколько стоит включить второй вызов» сегодня не отвечается ничем. Предмет пака-маршрутизатора, но сегодня он не записан нигде, и по этой же сетке будут выбирать порог за деньги | бэкенд | скоро | рядом с числом строк стоит их цена | сессия пака D39.257, её §10 | | 477 | **ЗАМЕР M2 — ПОПУЛЯЦИЯ КНИГ С ДВОЙНИКОМ КЛЮЧА НЕ ИЗМЕРЕНА, А НА НЕЙ СТОИТ ДОВОД «ПАК 1 БЕСПЛАТЕН ПО СНАПШОТАМ».** Прибор ряда 330 (`backend/internal/membank/memseed.go:714`=`func UnverifiedKeyConflicts`) ключуется на `entryFiringKeys`, поэтому пере-определённый вопрос M2 он вернёт тем же НУЛЁМ ПО ПОСТРОЕНИЮ — то есть «ноль» будет ответом прибора на свой вопрос, а не о предмете. Чтобы вопрос был задан, нужны три правки `membank`: снять пропуск пары подписанных (`backend/internal/membank/memseed.go:733`=`ApprovedSharedKeyCollisions`), снять пропуск одинаковой передачи (`backend/internal/membank/memseed.go:735`=`ei.Dst == ej.Dst`) и экспортировать порог ключа (`backend/internal/membank/memory.go:78`=`func minKeyLenFor`). ⚠ Значит это правка ДВИЖКА, а не $0-ресёрч, как значилось прежде. ⛔ Цена молчания: пока популяция не измерена, довод консилиума о бесплатности пака 1 по снапшотам остаётся недоказанным. Ряд 330 — ДРУГОЙ предмет (решение владельца по противоречию, цена там уже замерена на 142 книгах) | бэкенд | скоро | популяция книг с двойником ключа измерена прибором, который этот вопрос действительно задаёт | консилиум `D39.253` §3 строка 0-M2, ответ автора 16.09 | -| 478 | **ОРДИНАЛ БАТЧА ВХОДИТ В КЛЮЧ ПОКУПКИ ⇒ СНЯТИЕ ОДНОЙ РЕШЁННОЙ СТРОКИ ПЕРЕ-ПОКУПАЕТ ВСЕ ПОСЛЕДУЮЩИЕ БАТЧИ.** Ключ берёт номер куска (`backend/internal/pipeline/render.go:366`=`strconv.Itoa(req.ChunkIdx)`), а терминолог нумерует батчи порядком (`backend/internal/pipeline/terminologist.go:1201`=`Chapter: 0, ChunkIdx: i` (⚠ испр. 17.09: было :1003; в файле ДВА вхождения, цель — та, над которой стоит «the batch ordinal is the chunk index», а не проба планирования на :1165)). ⇒ когда фильтр решённого убирает кандидата из раннего батча, ординалы ВСЕХ следующих сдвигаются, хеши меняются, чекпойнт не находится — и они покупаются заново, ДАЖЕ когда их сообщения не изменились ни на байт. Замерено советчиком на купленном сырье B (батчи покупки 1 с номерами 1 и 2 стали в покупке 2 номерами 0 и 1), оба адреса пере-сняты оркестратором. ⛔ Бьёт прямо по экономике `D39.256`: чем лучше работает «решённое остаётся решённым», тем больше сдвиг ординалов и тем дороже он обходится. Комментарий у фильтра называет только смену СОСТАВА батча и про ординал молчит. ⛔ **ПОСЫЛКА ОПРОВЕРГНУТА ЗАМЕРОМ ЗОНЫ 17.09 — ряд остаётся ЛАТЕНТНЫМ.** Пере-мерено на НАСТОЯЩЕМ батчере, а не выведено: снятие одного решённого кандидата даёт **0 сдвигов из 246 снятий**, снятие блока при боевом размере батча — **0** и на 66, и на 300 кандидатах. ⭐ Ноль не слепота прибора: положительный контроль (убрать батч целиком) даёт **18 из 19**. Причина — боевые конфиги размер батча не задают, работает умолчание, и снятие строки перекладывает кандидатов ВНУТРИ батча, не меняя их числа. ⇒ ключ покупки не трогать, пере-чеканка не нужна. ⚠ Условие, при котором вывод перестаёт держаться (назвала зона): МЕЛКИЙ размер батча оживляет класс — при 400 рунах замер даёт 475 сдвигов. ⚠ Моя ошибка названа прямо: я пере-снял два адреса и НЕ проверил саму посылку на боевом батчере, вывод советчика поехал в трекер непроверенным | бэкенд | когда-нибудь (гейт: мелкий batch_runes) | посылка пере-мерена на боевом размере батча либо класс закрыт как латентный | `D39.257` п.7, замер сессии 17.09 | +| 478 | **ОРДИНАЛ БАТЧА ВХОДИТ В КЛЮЧ ПОКУПКИ ⇒ СНЯТИЕ ОДНОЙ РЕШЁННОЙ СТРОКИ ПЕРЕ-ПОКУПАЕТ ВСЕ ПОСЛЕДУЮЩИЕ БАТЧИ.** Ключ берёт номер куска (`backend/internal/pipeline/render.go:366`=`strconv.Itoa(req.ChunkIdx)`), а терминолог нумерует батчи порядком (`backend/internal/pipeline/terminologist.go:1328`=`Chapter: 0, ChunkIdx: i` (⚠ испр. 17.09: было :1003; в файле ДВА вхождения, цель — та, над которой стоит «the batch ordinal is the chunk index», а не проба планирования на `backend/internal/pipeline/terminologist.go:1293`=`paid, perr := r.bankCheckpointExists`)). ⇒ когда фильтр решённого убирает кандидата из раннего батча, ординалы ВСЕХ следующих сдвигаются, хеши меняются, чекпойнт не находится — и они покупаются заново, ДАЖЕ когда их сообщения не изменились ни на байт. Замерено советчиком на купленном сырье B (батчи покупки 1 с номерами 1 и 2 стали в покупке 2 номерами 0 и 1), оба адреса пере-сняты оркестратором. ⛔ Бьёт прямо по экономике `D39.256`: чем лучше работает «решённое остаётся решённым», тем больше сдвиг ординалов и тем дороже он обходится. Комментарий у фильтра называет только смену СОСТАВА батча и про ординал молчит. ⛔ **ПОСЫЛКА ОПРОВЕРГНУТА ЗАМЕРОМ ЗОНЫ 17.09 — ряд остаётся ЛАТЕНТНЫМ.** Пере-мерено на НАСТОЯЩЕМ батчере, а не выведено: снятие одного решённого кандидата даёт **0 сдвигов из 246 снятий**, снятие блока при боевом размере батча — **0** и на 66, и на 300 кандидатах. ⭐ Ноль не слепота прибора: положительный контроль (убрать батч целиком) даёт **18 из 19**. Причина — боевые конфиги размер батча не задают, работает умолчание, и снятие строки перекладывает кандидатов ВНУТРИ батча, не меняя их числа. ⇒ ключ покупки не трогать, пере-чеканка не нужна. ⚠ Условие, при котором вывод перестаёт держаться (назвала зона): МЕЛКИЙ размер батча оживляет класс — при 400 рунах замер даёт 475 сдвигов. ⚠ Моя ошибка названа прямо: я пере-снял два адреса и НЕ проверил саму посылку на боевом батчере, вывод советчика поехал в трекер непроверенным | бэкенд | когда-нибудь (гейт: мелкий batch_runes) | посылка пере-мерена на боевом размере батча либо класс закрыт как латентный | `D39.257` п.7, замер сессии 17.09 | | 479 | **ВАРИАНТЫ ЧЕРНОВИКОВ УХОДЯТ НАРУЖУ СКЛЕЕННЫМ ЯРЛЫКОМ, И КЛИЕНТ НЕ МОЖЕТ ПОКАЗАТЬ ИХ НА ЯЗЫКЕ ЧИТАТЕЛЯ.** В проекции банка вариант едет одной строкой вида «передача ×N», а при алиасе — с англоязычным хвостом про то, для какой поверхности он предложен: части (сама передача · число чанков · алиас) НЕ опубликованы отдельными полями. ⇒ платформа вынуждена везти это как непрозрачный текст, а разобрать ярлык у себя не вправе — движок держит парсер рядом с писателем именно потому, что второй, пере-выведенный, «продолжит работать до дня, когда у ярлыка появится поле, и тогда вернёт числа вместо ошибки». ⚠ Пара-специфики в форме нет, но **английский фрагмент в данных ломает общность по языку интерфейса**: ревью-вопрос «заработает ли пара, которой в репозитории ещё нет, без правки Go» здесь отвечается «нет на уровне ПОКАЗА». Лечение движковое: публиковать части ярлыка полями. Найдено платформенной сессией 17.09 на купленном сырье при исполнении п.4 аддендума владельца | бэкенд | когда-нибудь | части ярлыка опубликованы полями либо решено, что показ вариантов читателю не нужен | зона платформы 17.09, `D39.258` п.9 | | 480 | **В КОНТРАКТЕ ЖИВУТ НАДГРОБИЯ: 121 СТРОКА, КОТОРУЮ НЕ ОТДАЁТ НИКТО — и у одного куска нет носителя решения ВООБЩЕ.** Аудит 17.09 (сплошное чтение спеки и компаньона): мусора 3.5 % при 3497 строках, и это не забытый хлам — у каждого куска свой баннер «ретировано», то есть история, которой не хватило последнего шага. Состав: схема потолка в главах (46 строк, НОЛЬ ссылок во всём документе — единственный орфан из 68 схем, ретирована ордер-формой `0.11.0`, держится только генерённым кодом ЗАМОРОЖЕННОГО фронта) · локализованное сообщение и его поле в конверте ошибки (23 строки; ⛔ **пере-снято мной 17.09: ноль упоминаний в не-тестовом коде платформы** — и, по аудиту, ноль хитов по журналу решений и обоим бэклогам, то есть ЕДИНСТВЕННЫЙ кусок контракта без носителя решения) · поле потолка в заявке прогона (16 строк, ⚠ УДАЛЯТЬ НЕЛЬЗЯ: единственное `deprecated` в файле, оно РАБОТАЕТ отказом на входе, чтобы старый клиент не купил молча не то). ⚠ Снимать разумно ТЕМ ЖЕ актом, что синк зеркала фронта, иначе фронт при разморозке сгенерит их заново. ⚠ Локализованное сообщение либо обосновать нотой, либо снять: сегодня его не защищает ничто | платформа + оркестратор | когда-нибудь (вместе с синком зеркала при разморозке фронта) | мёртвые схемы сняты либо у каждой назван носитель решения | аудит контракта 17.09 | | 481 | **ОТКАЗ КНИЖНОГО ПОТОЛКА В БАНК-КОНТУРЕ ТЕРЯЕТ БАТЧИ ПОЗАДИ ОТКАЗАННОГО — включая УЖЕ ОПЛАЧЕННЫЕ, чей повтор стоил бы $0.** Цикл покупки банк-батчей на `errReserveCeiling` делает выход, и всё, что стояло в очереди после отказанного, не попадает НИ в счётчик выброшенных, ни в счётчик прошедших: единственный след — предупреждение посреди прохода. ⚠ Это противоречит правилу, которое пре-флайт того же контура объявляет у себя («деньги дороже проекции, но молчать о потере нельзя»), и **дефект ПРЕД-СУЩЕСТВУЕТ паку лестницы**: до неё потерянный батч и не покупался, после неё позади отказанного могут стоять оплаченные. Названо зоной в приёмочном круге 17.09 и сознательно НЕ чинено: смена поведения, которой пак не заказывал. Адрес — ветвь отказа резервации в цикле банк-ролей. ⛔ Цена молчания растёт вместе с механизмом «решённое остаётся решённым»: чем больше батчей переигрывается за ноль, тем дороже потерять их из-за отказа на соседнем | бэкенд | скоро | потерянные батчи попадают в счётчики либо выход заменён продолжением с честным учётом | зона `textmachine-main-12`, приёмочный круг 17.09 | @@ -394,7 +394,7 @@ | 483 | ⛔ **СПРАВОЧНИК ПРОВАЙДЕРСКИХ ЛОВУШЕК НЕСЁТ ЦЕНЫ, ОПРОВЕРГНУТЫЕ ПЕРЕ-ПИНОМ, И ЭТО ФАЙЛ, КОТОРЫЙ КАНОН ВЕЛИТ ЧИТАТЬ ПЕРЕД КАЖДЫМ ВЫЗОВОМ.** `docs/experiments/00-provider-quirks.md:35`=`НЕ изменились (flash` утверждает, что после смены поколения цены DeepSeek прежние — flash $0.14/$0.28 при кэш-хите $0.0028, pro $0.435/$0.87. Боевой конфиг несёт другое: `backend/configs/models.yaml:231`=`input_per_m: 0.44, cached_per_m: 0.014` и `backend/configs/models.yaml:247`=`input_per_m: 1.32, cached_per_m: 0.044`. ⇒ расхождение втрое по входу и вчетверо по выходу, а кэш-хит разошёлся на порядок. ⚠ Пинг об этом выписан оркестратором №18 ещё 20.08 и не исполнен год-в-год: тогда каталог считался чужой зоной. С `D39.260` п.4 зона ОБЩАЯ ПРОЕКТНАЯ ⇒ чинит оркестратор. Шапка исправлена 17.09, ряд держит остаток: пере-снять ВЕСЬ ценовой блок справочника у вендора, а не только одну строку | оркестратор | скоро | цены справочника сверены с боевым конфигом и вендором целиком | пинг №18 20.08, замер 17.09 | | 484 | ⛔ **РАТИФИЦИРОВАННЫЙ РЕЦЕПТ МУТАЦИЙ ТРЕБУЕТ ПАРАЛЛЕЛЬНЫХ БАТАРЕЙ, А БАТАРЕЯ ЗОНЫ СОДЕРЖИТ ФИКСТУРЫ С АБСОЛЮТНЫМИ СРОКАМИ И НАСТОЯЩИМ КОММИТОМ В POSTGRES — ЭТО КОНФЛИКТ ДВУХ РАТИФИЦИРОВАННЫХ ВЕЩЕЙ, А НЕ ДЕФЕКТ ОДНОГО ПАКЕТА.** `D39.159` §2 велит сажать мутации в КОПИЮ дерева ⇒ всякая приёмка гонит две батареи разом; пакет `platform/internal/books` при этом краснеет КАЖДЫЙ РАЗ НА ДРУГОМ ТЕСТЕ — подпись голодания планировщика, а не логики. ⭐ Измерено ДВАЖДЫ и двумя сторонами: зона — двумя полными батареями, запущенными в одну секунду (чистый `HEAD` и дерево пака красны ОБА, на РАЗНЫХ тестах); оркестратор при приёмке 17.09 — двумя изолированными прогонами пакета в двух деревьях одновременно: `ok 76.816s` и `ok 75.761s`, оба `GOTEST_EXIT=0` при нагрузке 6.05/6.21, тогда как внутри полной батареи тот же пакет красный. ⇒ изолированно зелен всегда, красен только под собственной батареей зоны с `-race` плюс сторонней нагрузкой. ⭐ **ТРЕТЬЕ ПОДТВЕРЖДЕНИЕ 17.09, приёмка `D39.265`, и ряд предсказал форму наблюдения ДОСЛОВНО:** гейт зоны на финальном дереве дал `MAKE_EXIT=2` на ДВУХ НОВЫХ именах того же файла (`TestAnUploadTheHostCouldNotCutStillLeavesSomebodyToFinishTheBook` и `TestAnUploadWithNoRoomLeftForACutSaysThatAndHandsTheBookOver`, обе за 1.1–1.2 с, обе `pgstore: commit: timeout`) — то есть «каждый раз на другом тесте» сбылось. Оба теста живут в чистом `HEAD`, паком не принесены. ⛔ **И ТОЧЕК ОТКАЗА У КЛАССА ДВЕ, А НЕ ОДНА — различение внесено по поправке зоны, чтобы следующая смена не искала одну причину:** (1) `commit: timeout` за секунду с небольшим упирается в ТЕСТОВЫЙ бюджет записи 20–25 мс, который фикстура ставит себе сама (боевой — 30 с, `parse.go`, греп `const writeBudget`, снаружи пакета недостижим); (2) исчерпание ПУЛА соединений с шестисотсекундным таймаутом `go test` — замер оркестратора на пяти изолированных кругах: **4 зелёных по 21–23 с, пятый завис** со стеком в `pgxpool/pool.go:333` при одиннадцати клиентских бэкендах стенда. ⚠ Округлить это до «изолированно зелен всегда» было соблазнительно и неверно. ⚠ Конкуренция за стенд названа УСЛОВИЕМ, а не доказанной причиной: зона пере-спросила стенд и показала, что к моменту разбора клиентский бэкенд в нём один; ходит ли мутационная кампания движка в этот Postgres — предположение (движок на SQLite проектных баз), а не замер. ⭐ Куплена норма, внесённая зоной в свой носитель: **два измерителя в одном стенде портят числа МОЛЧА, и порча выглядит как свойство предмета** — прогоны, делящие стенд, называют друг друга пингом, а перед объявлением флейка спрашивают сам стенд, кто в нём. **Механизм пере-снимался ТРИЖДЫ, и все три редакции стоит держать видимыми:** (1) «фикстуры сжимают продуктовые 220 с до 700 мс» — верно про `TestTheCutOfAnUploadIsBoundedByTheWalk…`, но падение приёмки не объясняет; (2) «фикстура называет посылку `on an idle host` четырежды и не проверяет её ни разу» (`Skip`/`loadavg`/`NumCPU` → 0) — верно по классу, но сжимает не она; (3) решающая, зоны: в `TestAnUploadThatRunsOutOfBudgetWaitingForASlot…` `uploadSettle = 0` ВОЗВРАЩАЕТ продуктовые 210 с, а режет невозвращённый `writeBudget = 20 мс`, поставленный для ПЕРВОЙ половины теста ⇒ падает утверждение «настоящий коммит укладывается в 20 мс», а называет себя оно «загрузка на простаивающем хосте». Лечение дешёвое: сбросить `writeBudget` вместе с `uploadSettle` либо дать второй половине свои бюджеты; сверх того — утверждать посылку простоя замером с внятным скипом или перестать зависеть от абсолютного времени. ⚠ **ГРАНИЦА СНЯТА ЗАМЕРОМ 17.09, и прежнюю оставляю видимой:** зона говорила «сколько тестов семейства подвержено — я НЕ измеряла; три теста за три прогона это ВСТРЕЧЕННОЕ, а не посчитанное», затем посчитала прогоном по всем тест-файлам пакета с разрешением констант — **6 тестов из 73** кладут настоящую операцию Postgres внутрь суб-секундного бюджета (`failfast_test.go` 1 · `limit_test.go` 4 · `walk_test.go` 1), и ВСЕ ЧЕТЫРЕ красневших — внутри этих шести, ни одного за их пределами. ⛔ **Четвёртый красный снёс довод о нагрузке:** `TestAnUploadTheHostCouldNotCutStillLeavesSomebodyToFinishTheBook` упал при длительностях пакетов, почти равных ЗЕЛЁНОМУ прогону (`pgstore` 322 против 317 с, `runs` 284 против 278, `books` 113 против 115) ⇒ грубого замедления не требуется, хватает МГНОВЕННОЙ ЗАМИНКИ, что для бюджета 20 мс поверх сетевого коммита ожидаемо. Носители: `PD-469` (диагноз, замер двумя деревьями) и `PD-420` (второе лицо того же конфликта, диагноз не установлен). ⛔ Цена бездействия названа: ложный красный у КАЖДОЙ будущей приёмки, и он неотличим от регрессии, пока кто-нибудь не потратит два прогона на разделение | платформа | скоро | фикстуры семейства не зависят от абсолютных сроков либо утверждают свою посылку; сосчитано, сколько тестов подвержено | приёмка 17.09, замеры зоны и оркестратора | | 485 | ⛔ **ПЕРВАЯ ВРЕЗКА ФАЙЛА, КОТОРЫЙ ЧИТАЕТ КАЖДАЯ ПОЛИГОН-СЕССИЯ ПРИ ОНБОРДИНГЕ, ДЕРЖИТ ЗАПРЕТ, СНЯТЫЙ ПОЛТОРА МЕСЯЦА НАЗАД.** `eval/README.md:7`=`Платные прогоны/докупки СТОП` объявляет «Платные прогоны/докупки СТОП до ре-пробы (бэклог-строка 74)», а строка **74 ЗАКРЫТА актом `D39.95` (02.08)**: в таблице трекера её нет вовсе (греп по номеру ряда → 0 при 354 рядах), ограничение пало лендингом 112. ⇒ обязательное чтение роли объявляет ЗАПРЕЩЁННЫМ то, что зона делает ежедневно, и этим обесценивает все прочие предупреждения того же файла — формулировка пинга оркестратора №20 от 02.09, не исполненного с тех пор. ⭐ **И вот что здесь дороже самого дефекта: норму против него сформулировал ТОТ ЖЕ акт, который закрыл строку.** `D39.95` записан в реестре с уроком «закрытие строки обязано триггерить греп по её номеру во всех живых доках» — и для строки 74 этот греп не сделан до сих пор, то есть нота не исполнила собственный вывод. ⇒ закрывать ряд надо ОБОИМИ движениями: снять врезку и прогнать греп по номерам закрытых строк по живым докам, иначе класс вернётся. ⚠ Живым из врезки остаётся ДРУГОЕ, и его не потерять: смена весов под тем же слагом (⚠0731) и стохастичность эха по вызову. ⚠ Заведено 17.09 при выносе хроники полигона в архив: по условию владельца (`D39.261` п.2) живое уезжает СТРОКОЙ ТРЕКЕРА прежде своего носителя. `eval/` — чужая зона, рукой не трогаю | полигон | скоро | врезка пере-написана под живое ограничение, и греп по номерам закрытых строк в живых доках даёт 0 | пинг №20 02.09, замер 17.09 | -| 487 | ⚠ **МАЙНЕР ПРОИЗВОДИТ СОСТОЯНИЕ, КОТОРОЕ ЧЕТЫРЕ ЕГО ЖЕ КОММЕНТАРИЯ ОБЪЯВЛЯЮТ НЕВОЗМОЖНЫМ: `status:auto` с НЕПУСТЫМ `dst`.** Движок утверждает «`auto` ⇒ dst нет, строка инертна» в четырёх местах: `backend/internal/miner/miner_emit.go:22`=`status:auto, no dst` · `miner_emit.go:53`=`inert until someone signs it` · `miner_emit.go:274`=`term with no dst stays` · `backend/internal/terminology/terminology.go:693`=`status:auto (inert)`. Но ветка `miner_emit.go:272-273` ставит `st.Dst = props[0].Dst` при `props[0].Via == ""` и статуса НЕ трогает (он остаётся `auto` из `:251`; `draft` выставляется только на `:279` при консолидированном dst) ⇒ рождается пара, которой двухрежимная эмиссия §C2-7 не предусматривает. ⛔ **Пина нет ни одного:** утверждений о паре статус/dst в тестах пакета майнера 0 при контроле «12 функций Test в трёх файлах»; ряда в трекере не было (0 по четырём шаблонам при контроле «майнер» → 12). ⚠ **ЧТО ИЗМЕРЕНО И ЧТО НЕТ, раздельно.** Измерено: состояние достижимо по коду и не запинено; на ПРОВОД оно не уходит — отбор в инжект требует `approved` и непустого dst (`backend/internal/membank/memory.go:1245`, `:442`), то есть денежной утечки здесь НЕТ. НЕ измерено: как такую строку читает ЧЕЛОВЕК в карте подписи — рядом стоит собственное предупреждение движка, что dst без провенанса приглашает владельца прочесть его как уже-канон (`appendProposalNote`). Это и есть вопрос ряда, а не утверждение. ⭐ Найдено 17.09 при разборе строки Д-3 консилиума: сама Д-3 ОТКЛОНЕНА (её адрес указывал в несуществующий путь, а по верному адресу ветка статуса не касается), но проверка её формулировки вскрыла это | бэкенд | скоро | пара статус/dst либо запинена как законная с объяснением, либо `auto` перестаёт получать dst | разбор Д-3, 17.09 | +| 487 | ⚠ **МАЙНЕР ПРОИЗВОДИТ СОСТОЯНИЕ, КОТОРОЕ ЧЕТЫРЕ ЕГО ЖЕ КОММЕНТАРИЯ ОБЪЯВЛЯЮТ НЕВОЗМОЖНЫМ: `status:auto` с НЕПУСТЫМ `dst`.** Движок утверждает «`auto` ⇒ dst нет, строка инертна» в четырёх местах: `backend/internal/miner/miner_emit.go:22`=`status:auto, no dst` · `backend/internal/miner/miner_emit.go:53`=`inert until someone signs it` · `backend/internal/miner/miner_emit.go:274`=`term with no dst stays` · `backend/internal/terminology/terminology.go:693`=`status:auto (inert)`. Но ветка `miner_emit.go:272-273` ставит `st.Dst = props[0].Dst` при `props[0].Via == ""` и статуса НЕ трогает (он остаётся `auto` из `:251`; `draft` выставляется только на `:279` при консолидированном dst) ⇒ рождается пара, которой двухрежимная эмиссия §C2-7 не предусматривает. ⛔ **Пина нет ни одного:** утверждений о паре статус/dst в тестах пакета майнера 0 при контроле «12 функций Test в трёх файлах»; ряда в трекере не было (0 по четырём шаблонам при контроле «майнер» → 12). ⚠ **ЧТО ИЗМЕРЕНО И ЧТО НЕТ, раздельно.** Измерено: состояние достижимо по коду и не запинено; на ПРОВОД оно не уходит — отбор в инжект требует `approved` и непустого dst (`backend/internal/membank/memory.go:1245`, `:442`), то есть денежной утечки здесь НЕТ. НЕ измерено: как такую строку читает ЧЕЛОВЕК в карте подписи — рядом стоит собственное предупреждение движка, что dst без провенанса приглашает владельца прочесть его как уже-канон (`appendProposalNote`). Это и есть вопрос ряда, а не утверждение. ⭐ Найдено 17.09 при разборе строки Д-3 консилиума: сама Д-3 ОТКЛОНЕНА (её адрес указывал в несуществующий путь, а по верному адресу ветка статуса не касается), но проверка её формулировки вскрыла это | бэкенд | скоро | пара статус/dst либо запинена как законная с объяснением, либо `auto` перестаёт получать dst | разбор Д-3, 17.09 | | 488 | ⛔ **ТЕСТ ГЕЙТА ГРУЗИТ ВЕСЬ МОДУЛЬ С СИНТАКСИСОМ И ТИПАМИ — 1.44 ГБ БЕЗ `-race`, 3.2 ГБ С НИМ, И РАСТЁТ ВМЕСТЕ С РЕПОЗИТОРИЕМ.** `backend/internal/archguard/shippingtree_test.go:34`=`Mode: packages.LoadAllSyntax, Tests: true` грузит `textmachine/backend/...` целиком ⇒ его память пропорциональна размеру РЕПО, а не предмету теста. Замерено зоной 17.09 после ТРЁХ убийств гейта подряд; пере-снято оркестратором чтением (`LoadAllSyntax` 1 хит, `Tests: true` 1 хит в пакете). ⭐ **ПРИЧИНА УТОЧНЕНА 17.09 ТРЕТЬИМ НЕЗАВИСИМЫМ ЗАМЕРОМ, и прежняя редакция ряда читалась опаснее правды: бьёт СУПЕРВИЗОР ФОНОВЫХ ЗАДАЧ ХАРНЕССА, а ПЕРЕДНИЙ ПЛАН ему не подчиняется.** Та же команда с теми же флагами в переднем плане проходит: `go test ./internal/archguard/ -race -count=1 -timeout=20m` → `ok 29.048s`, пик **3 418 648 kB (3.26 ГБ)**, совпавший с показанием семплера ДО КИЛОБАЙТА. ⇒ гейт в машину ПОМЕЩАЕТСЯ; не помещается он в фоновую задачу. Умерли ПЯТЬ версий причины (конкуренция наборов · параллелизм `-p` · тяжесть пакета конвейера · потолок cgroup · нехватка памяти машины), живёт одна. ⚠ Следствие для приёмок: «гнать гейт, когда рядом нет второго тяжёлого прогона» — НЕ лечение, а суеверие; лечение — гнать не в фоне. ⭐ **ВТОРАЯ УЛИКА 17.09, приёмочная: потолок фоновых задач НЕ ОДИНАКОВ У СЕССИЙ.** У зоны `make battery` целиком не прошёл ЧЕТЫРЕ раза (включая попытку на пустой машине); у оркестратора тот же гейт на копии того же дерева прошёл ЦЕЛИКОМ и В ФОНЕ с первого раза, при `MemFree` **0.5 ГБ** на старте — то есть в ХУДШИХ условиях по свободной памяти. ⇒ «гейт не помещается в машину» неверно даже как описание: он не помещается в ЧУЖУЮ фоновую задачу, и чья именно сессия его запускает — несущий параметр, а не деталь. ⛔ **Убивает не нехватка памяти и не потолок cgroup:** `memory.max = max` у обоих слайсов, `MemAvailable` держался ≈4.2 ГБ — падал **`MemFree`, до 110 МБ**, и супервизор бьёт по НЕМУ. ⇒ «свободных четыре гигабайта» ничего не гарантирует, и это практическое знание для всех зон, а не частность движка. ⭐ **Три версии причины, выдвинутые до замера, оказались ЛОЖНЫМИ, и это стоит держать видимым:** «конкуренция наборов» (убило в одиночку) · «параллелизм пакетов» (убило с `-p=2`) · «тяжёлый `internal/pipeline`» (замер: пик 313 МБ под `-race`). ⚠ **И контроль A/B едва не обманул в ОБРАТНУЮ сторону:** первая попытка шла с `-run TestShipping`, вернула `ok … [no tests to run]` и 126 МБ; прими зона этот «дешёвый базис» за `HEAD`, вышел бы вывод «пак утроил память» — из контроля, который НЕ ЗАПУСКАЛСЯ. Настоящее имя — `TestInvariantsHoldInTheShippingTree`. Честное A/B: чистый `HEAD` 1.44 ГБ против рабочего дерева 1.44 ГБ, разница **+0.3 %** ⇒ дефект НЕ от пака. ⚠ Границы: в батарейное подмножество каталога мутаций `archguard` НЕ входит (пере-снято оркестратором: 0 упоминаний при 491 записи и 280 в батарее), поэтому кампанию он не трогает — страдает только `make battery`. Родня — ряд **484** (ратифицированный рецепт, не помещающийся в машину, на которой его требуют гонять) | бэкенд | скоро | тест судит инварианты, не загружая весь модуль, либо гейт объявляет свою потребность в памяти и условие, при котором не запускается | замер зоны 17.09, контроли оркестратора | | 489 | ⚠ **РЕВИЗИЯ ДОКУМЕНТАЦИИ ЗОНЫ БЭКЕНДА (пинг оркестратора №22 от 04.09, 10 пунктов) ЖИВА НА ТРИНАДЦАТЫЙ ДЕНЬ — пере-снято 17.09 приборами, а не перечитыванием.** Пинг сидит семьюдесятью строками в журнале прогресса и адресован ЗОНЕ, которой сейчас нет (слот свободен), поэтому живое уезжает сюда прежде, чем носитель будет свёрнут (условие владельца `D39.261` п.2). **ИЗМЕРЕНО ЧЕТЫРЕ ЖИВЫХ:** (1) `backend/README.md` описывает инвариант канала через ключи, которые ЗАГРУЗКА ОТВЕРГАЕТ — «permissive» 1 хит, а настоящий механизм (метки контента против принимаемых меток) **0 хитов**; (2) оба PUML (`components.puml`, `pipeline.puml`) БЕЗ предупреждающего баннера в шапке, при том что карта доков подаёт их как текущие; (6) ⛔ **тяжелейший: ратифицированная норма зоны висит на ЗАКРЫТОЙ строке** — `backend/docs/DISCLOSURE_LAW_DESIGN.md:219-221` обусловливает себя словами «пока строка бэклога 246 открыта», и сам текст обещает «закроется 246 — оговорка снимается вместе с ней», НО ряд 246 закрыт лендингом (в таблице его нет, журнал решений подтверждает) ⇒ оговорка действует без предмета; (10) пакет `backend/internal/langscreen` существует и лежит на денежном пути вердиктов, а в README о нём **0 упоминаний**. ✅ **ИЗМЕРЕНО ЗАКРЫТЫМ ОДНО:** (7) «семь протухших токен-якорей в `backend/docs/`» — красных якорей с целью в этом каталоге **0** при 327 адресах. ⚠ **НЕ ИЗМЕРЕНО ПЯТЬ** (3 · 4 · 5 · 8 · 9): они про содержание прозы README и требуют чтения, а не грепа; «не измерено» здесь значит именно это, а не «исполнено». ⛔ Правит ЗОНА: `backend/` мне писать нельзя, и тринадцать дней простоя — следствие того, что пинг жил в журнале, а не строкой трекера. Нести в промт следующего бэкенд-пака | бэкенд | скоро | четыре живых пункта исполнены или названы неисполнимыми, пять неизмеренных измерены | пинг №22 04.09, замеры оркестратора 17.09 | | 490 | **РАЗРЫВ ОКОН ГЛАВ У БАНКОВЫХ СТРОК НЕ ПРОВЕРЯЕТ НИКТО — страж построен только для ГОЛОСОВ.** Загрузчик отбивает ПЕРЕСЕЧЕНИЕ окон и полисемию (`backend/internal/membank/memseed.go:201-236`), а РАЗРЫВ — `until_ch=3` при следующем `since_ch=5`, то есть глава 4 без закона — не ловится ничем. Готовый образец лежит рядом и построен для другой сущности: `backend/internal/membank/memvoice.go:271`=`func VoiceWindowGaps`, и его докблок объявляет разрыв у голосов ЗАКОННЫМ намеренно (`backend/internal/membank/memvoice.go:268`=`a deliberate gap`), поэтому он логирует, а не роняет. ⚠ **Контроль области напечатан, потому что отрицательный замер без него неотличим от непрочитанного:** в не-тестовых `.go` каталога `membank` — 11 совпадений `windowsOverlap` и 7 хитов `gap` ВНЕ голосов, и все семь про пропуски склонений в пост-чеке, то есть о другом предмете; стража разрыва у банковых строк среди них нет. ⛔ **Чем это стоит качества перевода:** преемник термина собирается тремя отдельными решениями владельца, и опечатка в границе оставляет главу без закона МОЛЧА — редактор переводит её без банка, а замечает это уже читатель книги. Проверка живёт над тем же документом решений: глаголов не добавляет, `DecisionsVersion` не двигает, контракт не трогает — $0. ⚠ Беря у образца форму, взять и его гарантию: намеренный разрыв законен и в сид-файле невидим, поэтому исход — громкая строка оператору, а не отказ загрузки | бэкенд | скоро | разрыв окон у банковых строк называется оператору тем же способом, что у голосов, и запинен посадкой, которая краснеет именно им | `research/35` N-7, замеры оркестратора 17.09 | @@ -405,8 +405,8 @@ | 496 | ⛔ **ЦЕЛЬ `battery-stand` НА GIT-ВОРКРИ НЕ ПРОХОДИТ ПО ПОСТРОЕНИЮ, И ЕЁ СОБСТВЕННОЕ ОБЕЩАНИЕ ИСПОЛНЯЕТСЯ НАОБОРОТ.** Рецепт ставит флаги ВНУТРИ команды (`backend/Makefile:140`=`TM_MINER_PARITY=1 TM_CHECKER_LABELS=1`), то есть у оператора выбора нет — «я неудачно запустил» тут неверный диагноз. `standdata.Root()` ищет корень по маркеру (`backend/internal/standdata/standdata.go:35`=`Root finds the repository root by MARKER`) и в воркри разрешается в корень ВОРКРИ, где `eval/.gitignore` исключает `data/` правилом-классом ⇒ путь по умолчанию указывает туда, где файла не может быть никогда. Замер 17.09: `eval/exp16/data` в воркри отсутствует, гиту файл неизвестен (`git ls-files --error-unmatch` — 0), в основном чекауте лежит (5 071 852 байта), и цель падает `TM_MINER_PARITY=1 but required data is missing`. ⛔ Комментарий цели обещает «при отсутствии данных ПАДАТЬ, чтобы наличие корпуса УТВЕРЖДАЛОСЬ, а не предполагалось» — на воркри она утверждает отсутствие стенда, которого нет только здесь, и её сообщение читается как находка о дереве. ⚠ Лечение — НЕ оверрайд пути: `TM_MINER_PARITY_CONTRAST=<путь в основном чекауте>` живёт на одной машине и умрёт при переносе, как умирают вычисленные адреса. У артефакта есть воспроизводимое происхождение — регенерируется из jieba 0.42.1 с запиненным SHA (`docs/experiments/16-bank-mining.md:183`=`jieba_dict_general_zh.txt`) ⇒ цель обязана либо регенерировать его, либо объявлять отсутствие стенда ОТДЕЛЬНЫМ исходом, а не падением. Пять корпусных тестов при поданном стенде проходят — прибор годен, негоден его путь по умолчанию | бэкенд | скоро | цель проходит на воркри без ручных оверрайдов, либо печатает «стенда нет» отдельным исходом, отличимым от падения | замер оркестратора 17.09 при приёмке `D39.266` | | 498 | ⛔⛔ **`prompt_override` НЕ СПРАШИВАЕТ ПРО ПАРУ, И ВСЕ ЧЕТЫРЕ БОЕВЫХ КОНФИГА УЖЕ НАЦЕЛЕНЫ НА `zh-ru` ⇒ АНГЛИЙСКАЯ КНИГА ПОЕДЕТ КИТАЙСКИМ ПРОМТОМ ПЕРЕВОДЧИКА МОЛЧА.** Конвенционный путь `//.md` падает ГРОМКО на отсутствующей паре именно затем, чтобы конвенции чужой пары не подставлялись тихо; `prompt_override` проверяет только ЧИТАЕМОСТЬ файла и про пару не спрашивает никогда. Замер с контролем (`tmctl manifest` на настоящей английской книге, `source_lang: en`): override на настоящий `backend/prompts/zh-ru/translator-banknote.md` → **`EXIT=0`**, конфиг грузится и в той же сводке печатает `en→ru`; контроль — override на несуществующий файл того же каталога → `EXIT=10` «prompt_override template … is not readable». ⇒ гард есть, но он про файл, а не про принадлежность. Зашито во ВСЕХ боевых: `backend/configs/pipeline-c1.yaml:77`, `backend/configs/pipeline-arm-glm.yaml:38`, `backend/configs/pipeline-arm-mistral.yaml:42` (все `../prompts/zh-ru/translator-banknote.md`), `backend/configs/pipeline-c2.yaml:43` (`../prompts/zh-ru/judge-selector.md`). ⛔ **Цена конкретна и она в КАЧЕСТВЕ, а не в падении:** английская книга получит промт, который велит «китайский 时辰 = 2 часа», «доля 成 — десятые» и требует банкнотную таблицу по китайским правилам. ⚠ Класс — «промт проверен НАЛИЧИЕМ файла, а не тем, чему он принадлежит»; это дверь, через которую возвращается латентный баг, ради которого конвенционный путь и сделан громким. **Обход данными существует** (своя пайплайн-копия книги с override на свою пару) и применён паком английской пары — но обход прячет цену: следующая пара наступит на то же и наступит молча. **Лечение:** override обязан лежать внутри каталога пары ЭТОЙ книги, иначе громкий отказ, называющий и путь, и пару; осознанный вариант роли (`editor-mono`, банкнота) этим не ломается — он и так в каталоге своей пары. ⚠ `PromptSHA256` берётся по СОДЕРЖИМОМУ, а не по пути ⇒ пере-снапшота правка не требует (предъявить замером до правки конфигов) | бэкенд | **скоро (БЛОКЕР ратификации готовности)** | ⚠ **ИСПР. 18.09 — ПРЕЖНИЙ КРИТЕРИЙ ОПИСЫВАЛ ФОРМУ, КОТОРУЮ МЫ ОТВЕРГЛИ, И ЗАКРЫВАТЬ РЯД ПО НЕМУ НЕЛЬЗЯ.** Он предписывал «гард отказывает на override вне каталога пары книги» — а это отменило бы **ратифицированное** свойство с живым пином `TestPromptOverrideIsPairAgnostic` (`backend/internal/config/prompt_pack_test.go:119`, гоняет три пары), чей докблок объявляет черновую стадию ЕДИНСТВЕННЫМ осознанным исключением из ролевой конвенции и говорит про ключ дословно «which is exactly what the convention keeps that key for». Сессия остановилась и пингнула вместо исполнения — по условию оркестратора, и условие окупилось: разрешение гарда было ошибкой оркестратора, не проверившего ратификацию. **НОВЫЙ КРИТЕРИЙ, по построенному:** ключ `prompt_variant` резолвит вариант роли ПО КОНВЕНЦИИ (`/<пара>/<роль>-<вариант>.md`) — достройка того, что данные уже используют именами `translator-banknote.md`/`editor-mono.md`; `prompt_override` сохраняет ратифицированное пар-агностичное значение и его пин **НЕ тронут ни строкой**; все четыре боевых конфига сняты с литерального `../prompts/zh-ru/…` и переведены на вариант; пин утверждает, что КАЖДАЯ стадия КАЖДОГО боевого конфига резолвится в каталог СВОЕЙ пары, считает по (конфиг, пара) и сообщает недобор числом; записи каталога с флагом `battery` | замер `textmachine-main-c5` 17.09 на английской книге, разрешение оркестратора | | 497 | ⛔ **ПИН КВАДРАТИЧНОСТИ ФЛЕЙКУЕТ НА ЗДОРОВОМ ДЕРЕВЕ И КРАСИТ ЧУЖОЙ ЛЕНДИНГ.** `TestEvidenceWindowsDoesNotGrowQUADRATICALLYWithTheBook` (`backend/internal/terminology/evidence_test.go:77`=`linear ≈4, quadratic ≈16`; размеры входа объявлены строками выше — `measure(2000)` и `measure(8000)`) утверждает ОТНОШЕНИЕ времён, и его докблок объясняет выбор так: «IT ASSERTS A RATIO, NOT A DURATION. A wall-clock threshold on a shared machine is a flake; the shape of the curve is the property». ⛔ **Посылка опровергнута замером: отношение защищает от РОВНОЙ нагрузки и слепо к её ИЗМЕНЕНИЮ между половинами.** Обе половины меряются ПОСЛЕДОВАТЕЛЬНО, а `go test ./...` гоняет пакеты параллельно — выросла контенция между малым и большим замером, и отношение раздулось, ничего об этом не сказав. ⚠ **Улика — два вердикта на ОДНОМ коммите `871e0af`:** приёмка оркестратора дала `MAKE_EXIT=0`, входная батарея следующей сессии — `MAKE_EXIT=2` с `ratio ×16.5` при пороге 16 (малый замер прошёл на 42.5 мс против изолированных 22, то есть уже вдвое медленнее). Изолированно пять прогонов оркестратора дают 4.3 · 4.3 · 3.1 · 4.6 · 5.7 — свойство ДЕРЖИТСЯ, негоден прибор. ⇒ **зелень приёмки была везением, а не замером**, и цена дефекта не в этом тесте, а в том, что он красит лендинг чужой зоны и заставляет её доказывать невиновность. **Форма лечения названа сессией:** мерить половины ВПЕРЕМЕЖКУ (A-B-A-B, брать медиану) либо нормировать на опорный замер той же секунды — тогда общая нагрузка сокращается по-настоящему, а не по предположению. ⚠ Родня ряда про «пин, флейковый на мутанте, измеряет пустой сценарий», но здесь хуже: флейк на ЗДОРОВОМ дереве ⚠ **ТРЕТИЙ СВИДЕТЕЛЬ 18.09:** на этом пине упала батарея сессии достижимости пар-данных, и нагрузку создавал ЕЁ ЖЕ ревью-агент — то есть пин красит лендинг от работы, которую ведёт сама сдающая сессия. ⇒ класс подтверждён третий раз за двое суток: **пин, утверждающий отношение времён, на общей машине меряет нагрузку вместе с предметом**, и «своя» нагрузка не отличается от чужой. | бэкенд | скоро | пин краснеет только на настоящей квадратичности: посадка «вернуть квадратичный `window()`» краснеет им, а десять прогонов полной батареи подряд — зелёные | найдено `textmachine-main-c5` на входной батарее 17.09, пере-снято оркестратором пятью изолированными прогонами | -| 499 | ⛔ **ЭПИГРАФ ПРИЕЗЖАЕТ РАССЫПАННЫМ НА ТИПОГРАФСКИЕ СТРОКИ — НО ВИНОВАТ НЕ ДВИЖОК, А КОНВЕРТЕР ИЗДАТЕЛЯ; И ВТОРАЯ ФОРМА ЯВЛЕНИЯ ДВИЖКУ ВООБЩЕ НЕ ВИДНА.** ⚠ **ЧЕТВЁРТАЯ РЕДАКЦИЯ 18.09. Три предыдущие называли РАЗНЫЕ механизмы, и все три были неверны** — это носитель того, как дорого обходится объяснение вместо замера: (1) «вложенность блочной цитаты умножает переносы» — опровергнуто: `backend/internal/chunk/chunker.go:470`=`func splitParagraphs(chapter string) []string` делит по `\n\n` и ОТБРАСЫВАЕТ пустое; (2) «`

` внутри `

` есть строка стиха» — опровергнуто ЗАМЕРОМ по самому epub ДВУМЯ независимыми приборами (сессия `textmachine-main-c5` разбором 126 документов и советчик оркестратора): тегов `

` внутри цепочек `blockquote` **НОЛЬ**; (3) «это стих» — тоже неверно. ⭐ **ЧТО В МАТЕРИАЛЕ НА САМОМ ДЕЛЕ:** цепочек `blockquote` **88**, пустых 0, и **87 из 88 содержат ровно ОДНУ строку**, медиана длины **32 знака**; подряд идущие строки складываются в СВЯЗНУЮ ПРОЗУ эпиграфа, разбитую конвертером по ширине набора, а вложенность по CSS самого файла означает типографский ОТСТУП (`margin-left`), то есть след конвертера, а не структуру. `
` в книге **0**. ⇒ движок ведёт себя верно: он получает N абзацев и отдаёт N абзацев; беда в том, что издательский epub потерял границу между СТРОКОЙ и АБЗАЦЕМ ещё до нас. ⛔ **ВТОРАЯ ФОРМА, найденная только 18.09 и невидимая прежним замерам:** гимны и песни В ТЕЛЕ глав набраны не цепочками, а **курсивными абзацами по строке** — **154 строки в 32 блоках**. Движок их не видит ВООБЩЕ, потому что курсив до чанка не доезжает (ряд **500**): в обходчике ингеста ноль веток для инлайн-разметки, текст пишется безусловно (`backend/internal/chunk/ingest.go:1230`=`body.WriteString(text)`). ⇒ **суммарно ≈242 строки, а не 88.** ⛔ **ЛЕЧЕНИЕ — НЕ ДЕТЕКТОР, и это решение консилиума:** движок НЕ выносит вердикт «это стих»; он ДОНОСИТ СТРУКТУРУ на провод (образец — `pandoc`), а решает модель. Вторая форма закрывается починкой курсива из ряда 500 сама собой: прогон коротких помеченных абзацев модель опознаёт как стих без всякого порога. Первая форма закрывается языко-слепым правилом пары «несколько коротких абзацев подряд, каждый продолжает предыдущий, и ни один не реплика». ⛔ **ОТВЕРГНУТО ДВАЖДЫ и повторно подтверждено замером:** эвристика «абзац не кончается знаком конца предложения ⇒ это строка» есть ветвление по языку (знаки у пар разные) И вдобавок меряет не то: разбор «726 рваных абзацев» дал заголовки, обрывки оглавления и реплики, оборванные тире, — стиха среди них НЕТ. ⚠ Числа двух приборов не складывать: 726 снято регекспом сессии, 573 — прибором советчика на другой популяции. ⚠ Адрес `ingest.go:614` из полигонного письма относится к ДРУГОМУ чекауту (ветка `polygon` в `textmachine`), здесь `blockTags` на `:978` — различие деревьев, не ошибка автора | бэкенд | скоро (идёт ОДНИМ паком с рядом 500: носитель обеих форм — инлайн-разметка, и чинятся они одной правкой ингеста) | структура исходника доезжает до модели разметкой, а не теряется: курсивный спан приходит помеченным, прогон коротких строк опознаваем без порога и без ветвления по языку; пин на сквозной путь «разметка в epub → маркер в чанке → тег в экспорте», а не два пина по краям | замер `textmachine-main-c5` 17.09, ПЕРЕ-СНЯТ и опровергнут дважды 18.09; четвёртая редакция стоит на двух независимых разборах epub плюс замере оркестратора по коду ингеста | -| 501 | ⚠ **АНГЛИЙСКАЯ ОСЬ ПОЛИГОНА СНЯТА НА СПЛОШНОМ БЛОКЕ: ИСКАЖЁН АБСОЛЮТНЫЙ УРОВЕНЬ, КОНТРАСТЫ АРМОВ ЦЕЛЫ.** ⛔ **Разметка: это утверждение ПОЛИГОНА (`textmachine-b5`) о собственной работе, оркестратором НЕ пере-снятое**; носителем оно стало потому, что на этих числах стоят промты боевой английской пары — то есть предмет ратификаций, а не внутреннее дело зоны. Английский экстрактор полигона (`pair_en.raw_text`) сносил из epub теги регексом вместе с `

`: `eval/dovodka/podacha.py:19`=`11 447 абзацев, медиана 62 знака` — модель получала сплошной блок вместо одиннадцати тысяч абзацев. **Затронуты ВСЕ 273 английские клетки**, а не отдельные армы: восстановленную подачу получает единственный арм `RA` (`eval/dovodka/rol.py:162`=`RESTORE_ARMS = ("RA",)`), и он НЕ КУПЛЕН — 0 клеток ⇒ **цена дефекта не измерена ни разу**. ⭐ **Но контрасты держатся, и дефект был обойдён ОСОЗНАННО, а не пропущен:** вход у всех армов одинаково плоский, и довод автора стоит в самом коде (`eval/dovodka/rol.py:126`=`RA / RN — эффект ПОДАЧИ`; парная строка выше даёт `RN / ZP` как эффект ПРОМТА при одинаковом входе) ⇒ сравнение армов между собой чисто, искажён общий УРОВЕНЬ, на котором стоят все. **Уцелевает:** контрасты промтов и топологий (`RB > RC > RN`), вендорские сравнения, основание выбора формулировки владельца. **НЕ уцелевает:** любое утверждение об АБСОЛЮТНОМ качестве английского текста, о вёрстке, об абзацном строе и длине абзаца — и любой перенос английского числа на пару, где исходник абзацы не терял. **Два числа боевых промтов en-ru стоят на этом и помечены в доке зоны в месте цитирования:** вес ролевого промта 1.50/1.13 и «редактор на английском покупает» 1.22 против 2.78 ошибок на единицу — оба судейские, на английской панели, при разрешении прибора `eval/dovodka/KONSILIUM-22-08.md:159`=`разрешение 1.63 места на китайском` против 2.15 на английском. ⛔ **Починка экстрактора ретроактивно обнуляет адресацию купленного:** uid единицы есть `sha1(source.strip())`, любая правка пробелов переименовывает ВСЕ единицы — 289 оплаченных клеток на $2.64 теряют адресата вместе с судейскими ответами; поэтому диспозиция зоны (`eval/dovodka/KONSILIUM-22-08.md:141`=`Починка экстрактора абзацев`) велит чинить НА ПОДАЧЕ (`eval/dovodka/podacha.py:203`=`def restore_paragraphs`), сохраняя uid. ⚠ **Не путать с рядом 499:** там дефект ДВИЖКА (`

` внутри `

` читается как абзац прозы), здесь — дефект ПОЛИГОННОГО экстрактора (регексп снёс `

`); одной правкой не чинятся и в один ряд не сливаются. ⚠ **Третья оговорка автора, без которой ряд придётся переписывать:** после починки ингеста движка старые полигонные числа станут НЕСОПОСТАВИМЫ с новыми движковыми — они сняты на разном тексте, и следующая смена иначе сравнит несравнимое. Китайская пара не затронута вовсе: исходник txt, абзацы не терялись, арма `RA` у неё «нет и быть не может» | полигон (носитель — оркестратор) | скоро (гейт: перед любым ПЕРЕНОСОМ английского числа полигона в ратификацию) | ⚠ **КРИТЕРИЙ ПЕРЕ-РЕШЁН 18.09 ПО ВОЗРАЖЕНИЮ АВТОРА НАХОДКИ, и прежний был слабее:** я ставил закрытием «носить пометку», то есть документировал предмет бессрочно вместо того, чтобы его закрыть. Пометка не несёт МАСШТАБА — из неё нельзя узнать, искажение это два процента или полтора места, — и потому обесценивает чистые числа ровно настолько же, насколько защищает грязные. **Закрывается:** куплен арм `RA` (16 единиц, промт и жилец как у `RN`, отличие ТОЛЬКО в подаче) и контраст `RA/RN` даёт число цены подачи. ⛔ **Ограничение покупки, без которого она бесполезна:** `RA` берётся на ТОМ ЖЕ жильце и с ТЕМ ЖЕ уровнем усилия, что `RN` (`eval/dovodka/rol.py:623`=`dspro: вендор-дефолт high` — оба на вендор-дефолте), иначе контраст смешает подачу с усилием и родит второй такой же ряд вместо закрытия первого. **До покупки** каждое английское число полигона в носителях несёт пометку «абсолютный уровень искажён, контраст чист, **величина искажения НЕ измерена**»; пометка ВРЕМЕННАЯ и снимается или уточняется величиной по итогу `RA/RN`. ⚠ **Цена — вход владельцу, а не санкция:** ≈$0.45–0.51 (сумма купленных клеток `RB` $0.5089 и `RN` $0.4454 — пере-снято оркестратором, сошлось до цента; ⚠ знаменатель расходится по провенансу: 16 ЕДИНИЦ против 32 ФАЙЛОВ, у каждой единицы есть спутник `.ERROR.json`, и медиана по файлам вчетверо ниже медианы по единицам). ⚠ **История оси несёт 402, но единиц НЕ теряла — пере-снято оркестратором 18.09 по артефактам:** английских записей об ошибке 52, ненулевых по цене среди них 0, по роду — 44 × `APIStatusError 402 Insufficient` (упор в баланс провайдера), 5 × `RateLimitError 429`, 2 × `APIConnectionError`, 1 × `BadRequestError 400`. ⛔ **Но у КАЖДОЙ ошибочной единицы есть та же единица с содержимым** (пересечение uid: `RB` 16/16, `RC` 16/16, `RN` 14/14, `RGT` 5/5), потерянных единиц НОЛЬ, и у всех тринадцати армов ровно по 16 единиц с содержимым ⇒ риг ретраил и добирал состав полностью. ⇒ **опасение «покупка потребует второго захода» замером НЕ поддержано**, а требование считать контраст по пересечению непустых остаётся верным по другой причине: у `RN` одна из 16 единиц несёт ПУСТОЕ содержимое (класс «доставленная пустота», ряды 414–415). ⚠ Провенанс счёта: «273 английские клетки» есть ФАЙЛЫ (включая спутники `.ERROR.json`), единиц с содержимым по 16 на арм. Зона полигона выведена из скоупа словом владельца 11.09 ⇒ покупку решает ОН | утверждение `textmachine-b5` 18.09; все пять адресов пере-проверены оркестратором | +| 499 | ⛔ **ЭПИГРАФ ПРИЕЗЖАЕТ РАССЫПАННЫМ НА ТИПОГРАФСКИЕ СТРОКИ — НО ВИНОВАТ НЕ ДВИЖОК, А КОНВЕРТЕР ИЗДАТЕЛЯ; И ВТОРАЯ ФОРМА ЯВЛЕНИЯ ДВИЖКУ ВООБЩЕ НЕ ВИДНА.** ⚠ **ЧЕТВЁРТАЯ РЕДАКЦИЯ 18.09. Три предыдущие называли РАЗНЫЕ механизмы, и все три были неверны** — это носитель того, как дорого обходится объяснение вместо замера: (1) «вложенность блочной цитаты умножает переносы» — опровергнуто: `backend/internal/chunk/chunker.go:470`=`func splitParagraphs(chapter string) []string` делит по `\n\n` и ОТБРАСЫВАЕТ пустое; (2) «`

` внутри `

` есть строка стиха» — опровергнуто ЗАМЕРОМ по самому epub ДВУМЯ независимыми приборами (сессия `textmachine-main-c5` разбором 126 документов и советчик оркестратора): тегов `

` внутри цепочек `blockquote` **НОЛЬ**; (3) «это стих» — тоже неверно. ⭐ **ЧТО В МАТЕРИАЛЕ НА САМОМ ДЕЛЕ:** цепочек `blockquote` **88**, пустых 0, и **87 из 88 содержат ровно ОДНУ строку**, медиана длины **32 знака**; подряд идущие строки складываются в СВЯЗНУЮ ПРОЗУ эпиграфа, разбитую конвертером по ширине набора, а вложенность по CSS самого файла означает типографский ОТСТУП (`margin-left`), то есть след конвертера, а не структуру. `
` в книге **0**. ⇒ движок ведёт себя верно: он получает N абзацев и отдаёт N абзацев; беда в том, что издательский epub потерял границу между СТРОКОЙ и АБЗАЦЕМ ещё до нас. ⛔ **ВТОРАЯ ФОРМА, найденная только 18.09 и невидимая прежним замерам:** гимны и песни В ТЕЛЕ глав набраны не цепочками, а **курсивными абзацами по строке** — **154 строки в 32 блоках**. ⚠ **ИСПР. 18.09 — ЭТО УТВЕРЖДЕНИЕ ПРОТУХЛО И БЫЛО ЛОЖНЫМ РОВНО ПРО ЭТУ КНИГУ.** Прежняя редакция: «движок их не видит ВООБЩЕ, потому что курсив до чанка не доезжает (ряд 500): в обходчике ингеста ноль веток для инлайн-разметки, текст пишется безусловно». **Ряд 500 ЗАКРЫТ и снят с таблицы**, ветки построены: всякая запись в тело идёт через один сток (`backend/internal/chunk/ingest.go:1201`=`out := func(s string)`), курсивный прогон буферизуется и помечается (`backend/internal/chunk/ingest.go:1223`=`body.WriteString(ir.wrap(run))`). ⇒ **курсив доезжает до модели и возвращается читателю.** ⛔ И условие, при котором это перестаёт держаться, названо: механизм включается ДАННЫМИ ПАРЫ и молчит при `ir == nil`; объявляет его сегодня ОДИН файл — `backend/configs/langpacks/en-ru/inline-markup.txt` (у `zh-ru` такого файла нет), то есть у английской пары курсив едет, у китайской — нет, и это ПРАВИЛЬНО, а не дыра. ⇒ **из двух форм явления вторая теперь ВИДНА, но видна как ВЫДЕЛЕНИЕ, а не как СТИХ:** курсив не есть сигнал стиха, и граница СТРОКИ против АБЗАЦА потеряна конвертером издателя у обеих форм одинаково. Это не ослабляет вывод строки, а усиливает его: корень у обеих форм один. ⇒ **суммарно ≈242 строки, а не 88.** ⛔ **ЛЕЧЕНИЕ — НЕ ДЕТЕКТОР, и это решение консилиума:** движок НЕ выносит вердикт «это стих»; он ДОНОСИТ СТРУКТУРУ на провод (образец — `pandoc`), а решает модель. Вторая форма закрывается починкой курсива из ряда 500 сама собой: прогон коротких помеченных абзацев модель опознаёт как стих без всякого порога. Первая форма закрывается языко-слепым правилом пары «несколько коротких абзацев подряд, каждый продолжает предыдущий, и ни один не реплика». ⛔ **ОТВЕРГНУТО ДВАЖДЫ и повторно подтверждено замером:** эвристика «абзац не кончается знаком конца предложения ⇒ это строка» есть ветвление по языку (знаки у пар разные) И вдобавок меряет не то: разбор «726 рваных абзацев» дал заголовки, обрывки оглавления и реплики, оборванные тире, — стиха среди них НЕТ. ⚠ Числа двух приборов не складывать: 726 снято регекспом сессии, 573 — прибором советчика на другой популяции. ⚠ Адрес `ingest.go:614` из полигонного письма относится к ДРУГОМУ чекауту (ветка `polygon` в `textmachine`), здесь `blockTags` на `:978` — различие деревьев, не ошибка автора | бэкенд | скоро (идёт ОДНИМ паком с рядом 500: носитель обеих форм — инлайн-разметка, и чинятся они одной правкой ингеста) | структура исходника доезжает до модели разметкой, а не теряется: курсивный спан приходит помеченным, прогон коротких строк опознаваем без порога и без ветвления по языку; пин на сквозной путь «разметка в epub → маркер в чанке → тег в экспорте», а не два пина по краям | замер `textmachine-main-c5` 17.09, ПЕРЕ-СНЯТ и опровергнут дважды 18.09; четвёртая редакция стоит на двух независимых разборах epub плюс замере оркестратора по коду ингеста | +| 501 | ⚠ **АНГЛИЙСКАЯ ОСЬ ПОЛИГОНА СНЯТА НА СПЛОШНОМ БЛОКЕ: ИСКАЖЁН АБСОЛЮТНЫЙ УРОВЕНЬ, КОНТРАСТЫ АРМОВ ЦЕЛЫ.** ⛔ **Разметка: это утверждение ПОЛИГОНА (`textmachine-b5`) о собственной работе, оркестратором НЕ пере-снятое**; носителем оно стало потому, что на этих числах стоят промты боевой английской пары — то есть предмет ратификаций, а не внутреннее дело зоны. Английский экстрактор полигона (`pair_en.raw_text`) сносил из epub теги регексом вместе с `

`: `eval/dovodka/podacha.py:19`=`11 447 абзацев, медиана 62 знака` — модель получала сплошной блок вместо одиннадцати тысяч абзацев. **Затронуты ВСЕ 273 английские клетки**, а не отдельные армы: восстановленную подачу получает единственный арм `RA` (`eval/dovodka/rol.py:162`=`RESTORE_ARMS = ("RA",)`), и он НЕ КУПЛЕН — 0 клеток ⇒ **цена дефекта не измерена ни разу**. ⭐ **Но контрасты держатся, и дефект был обойдён ОСОЗНАННО, а не пропущен:** вход у всех армов одинаково плоский, и довод автора стоит в самом коде (`eval/dovodka/rol.py:125`=`RA / RN — эффект ПОДАЧИ`; парная строка выше даёт `RN / ZP` как эффект ПРОМТА при одинаковом входе) ⇒ сравнение армов между собой чисто, искажён общий УРОВЕНЬ, на котором стоят все. **Уцелевает:** контрасты промтов и топологий (`RB > RC > RN`), вендорские сравнения, основание выбора формулировки владельца. **НЕ уцелевает:** любое утверждение об АБСОЛЮТНОМ качестве английского текста, о вёрстке, об абзацном строе и длине абзаца — и любой перенос английского числа на пару, где исходник абзацы не терял. **Два числа боевых промтов en-ru стоят на этом и помечены в доке зоны в месте цитирования:** вес ролевого промта 1.50/1.13 и «редактор на английском покупает» 1.22 против 2.78 ошибок на единицу — оба судейские, на английской панели, при разрешении прибора `eval/dovodka/KONSILIUM-22-08.md:159`=`разрешение 1.63 места на китайском` против 2.15 на английском. ⛔ **Починка экстрактора ретроактивно обнуляет адресацию купленного:** uid единицы есть `sha1(source.strip())`, любая правка пробелов переименовывает ВСЕ единицы — 289 оплаченных клеток на $2.64 теряют адресата вместе с судейскими ответами; поэтому диспозиция зоны (`eval/dovodka/KONSILIUM-22-08.md:141`=`Починка экстрактора абзацев`) велит чинить НА ПОДАЧЕ (`eval/dovodka/podacha.py:203`=`def restore_paragraphs`), сохраняя uid. ⚠ **Не путать с рядом 499:** там дефект ДВИЖКА (`

` внутри `

` читается как абзац прозы), здесь — дефект ПОЛИГОННОГО экстрактора (регексп снёс `

`); одной правкой не чинятся и в один ряд не сливаются. ⚠ **Третья оговорка автора, без которой ряд придётся переписывать:** после починки ингеста движка старые полигонные числа станут НЕСОПОСТАВИМЫ с новыми движковыми — они сняты на разном тексте, и следующая смена иначе сравнит несравнимое. Китайская пара не затронута вовсе: исходник txt, абзацы не терялись, арма `RA` у неё «нет и быть не может» | полигон (носитель — оркестратор) | скоро (гейт: перед любым ПЕРЕНОСОМ английского числа полигона в ратификацию) | ⚠ **КРИТЕРИЙ ПЕРЕ-РЕШЁН 18.09 ПО ВОЗРАЖЕНИЮ АВТОРА НАХОДКИ, и прежний был слабее:** я ставил закрытием «носить пометку», то есть документировал предмет бессрочно вместо того, чтобы его закрыть. Пометка не несёт МАСШТАБА — из неё нельзя узнать, искажение это два процента или полтора места, — и потому обесценивает чистые числа ровно настолько же, насколько защищает грязные. **Закрывается:** куплен арм `RA` (16 единиц, промт и жилец как у `RN`, отличие ТОЛЬКО в подаче) и контраст `RA/RN` даёт число цены подачи. ⛔ **Ограничение покупки, без которого она бесполезна:** `RA` берётся на ТОМ ЖЕ жильце и с ТЕМ ЖЕ уровнем усилия, что `RN` (`eval/dovodka/rol.py:623`=`dspro: вендор-дефолт high` — оба на вендор-дефолте), иначе контраст смешает подачу с усилием и родит второй такой же ряд вместо закрытия первого. **До покупки** каждое английское число полигона в носителях несёт пометку «абсолютный уровень искажён, контраст чист, **величина искажения НЕ измерена**»; пометка ВРЕМЕННАЯ и снимается или уточняется величиной по итогу `RA/RN`. ⚠ **Цена — вход владельцу, а не санкция:** ≈$0.45–0.51 (сумма купленных клеток `RB` $0.5089 и `RN` $0.4454 — пере-снято оркестратором, сошлось до цента; ⚠ знаменатель расходится по провенансу: 16 ЕДИНИЦ против 32 ФАЙЛОВ, у каждой единицы есть спутник `.ERROR.json`, и медиана по файлам вчетверо ниже медианы по единицам). ⚠ **История оси несёт 402, но единиц НЕ теряла — пере-снято оркестратором 18.09 по артефактам:** английских записей об ошибке 52, ненулевых по цене среди них 0, по роду — 44 × `APIStatusError 402 Insufficient` (упор в баланс провайдера), 5 × `RateLimitError 429`, 2 × `APIConnectionError`, 1 × `BadRequestError 400`. ⛔ **Но у КАЖДОЙ ошибочной единицы есть та же единица с содержимым** (пересечение uid: `RB` 16/16, `RC` 16/16, `RN` 14/14, `RGT` 5/5), потерянных единиц НОЛЬ, и у всех тринадцати армов ровно по 16 единиц с содержимым ⇒ риг ретраил и добирал состав полностью. ⇒ **опасение «покупка потребует второго захода» замером НЕ поддержано**, а требование считать контраст по пересечению непустых остаётся верным по другой причине: у `RN` одна из 16 единиц несёт ПУСТОЕ содержимое (класс «доставленная пустота», ряды 414–415). ⚠ Провенанс счёта: «273 английские клетки» есть ФАЙЛЫ (включая спутники `.ERROR.json`), единиц с содержимым по 16 на арм. Зона полигона выведена из скоупа словом владельца 11.09 ⇒ покупку решает ОН | утверждение `textmachine-b5` 18.09; все пять адресов пере-проверены оркестратором | | 502 | ⚠ **ПОЛОВИНА ЗАКРЫТА 18.09 актом `D39.268`:** имя исчерпания средств провайдера печатается человеку — в последней строке прогона и в записи об ошибке. **ОСТАЁТСЯ ПРОГРАММНАЯ ПОЛОВИНА:** нового кода возврата и нового слова в словаре кадров НЕ добавлено намеренно — словарь есть замороженный шов, и его расширение является решением, а не правкой пака. ⛔ **УПОР В БАЛАНС ПРОВАЙДЕРА НЕ ИМЕЕТ СОБСТВЕННОГО ИСХОДА: ПРОВОД КЛАССИФИЦИРУЕТ ЕГО ВЕРНО, А ОПЕРАТОР ПОЛУЧАЕТ ОБЫЧНОЕ ТЕРМИНАЛЬНОЕ ПАДЕНИЕ СТАДИИ.** ⚠ Разметка честная: **снято ЧТЕНИЕМ КОДА, живого 402 не исполнял** — движок в этом состоянии не гонялся. **Что построено и работает:** `backend/internal/llm/httpllm.go:691`=`func retryableStatus(status int, body []byte) bool` есть ЕДИНСТВЕННЫЙ источник раздела «повторять/терминально» и стережётся дрейф-гардом; 402 терминален по умолчанию (`:698`=`terminal 4xx (incl. 402 Payment Required)`), а 429 с телом об исчерпанных кредитах тоже терминален — узкий набор маркеров `:710`=`insufficient_quota` / `quota_exceeded`, и довод стоит рядом: повтор под удержанной резервацией жжёт только время, потому что «the operator must top up». ⇒ **денег на пустые ретраи мы не тратим, и это важно сказать первым.** ⛔ **Дыра выше провода:** типизированный `HTTPStatusError` (`backend/internal/llm/httpllm.go:717`) не покидает пакет `llm` — 7 упоминаний, ВСЕ в `internal/llm`, в конвейере ноль; ошибка едет наверх обёрнутым текстом (`%w`), а перечислимых причин в `backend/internal` **43**, и **ни одна** не про кредиты провайдера (контроль: строк со словом `reason` — 943; единственный хит шаблона «причина + кредиты» — посторонний комментарий `backend/internal/pipeline/rebill.go:269`). ⇒ «у провайдера кончились деньги» и «стадия упала терминально» на уровне ИСХОДА неразличимы; тело ответа провайдера доезжает до человека только внутри текста обёрнутой ошибки. ⛔ **Почему это гейт готовности, а не гигиена:** предстоят ДВЕ книги по 20 глав ПАРАЛЛЕЛЬНО, и прогон, встретивший 402 на середине, останавливается наполовину купленным; оператору нужно за секунды отличить «пополни счёт» от «движок сломался», а сегодня он это читает из текста ошибки. ⚠ **Событие не гипотетическое:** на английской оси полигона 44 записи об ошибке из 52 — ровно `APIStatusError 402 Insufficient` (ряд **501**), то есть провайдер уже упирался в баланс, и заметили это постфактум, разбирая артефакты. | бэкенд | **скоро (кандидат в блокеры ратификации готовности к эксперименту двух переводов)** | у исчерпания кредитов провайдера есть НАЗВАННЫЙ исход, отличимый от обычного терминального падения стадии, и он виден оператору прогона; пин краснеет, когда тело с 402 превращается в родовую причину | замер оркестратора 18.09 чтением кода; повод — находка `textmachine-b5` о 44 отказах по балансу на английской оси | | 503 | ⛔ **ЗАБОР РЕ-ПИНА ПРОПУСКАЕТ ТОЛЬКО ОДНУ ОСЬ, ПОЭТОМУ КАЖДОЕ СЛЕДУЮЩЕЕ ОБЪЯВЛЕНИЕ ПАРЫ БУДЕТ ПЕРЕПОКУПАТЬ БАЙТ-ИДЕНТИЧНЫЕ КНИГИ.** Движок УЖЕ умеет исход «снапшот двинулся, а байты нет — $0»: это ре-пин (`backend/internal/pipeline/repin.go:61`=`func classifySnapshotMove`). Но забор пускает в него ровно ОДНУ ось — банк памяти; любое иное расхождение полей классифицируется как «прочее» и требует полной перепокупки. ⇒ когда пара объявит опциональный пар-файл (любой из контракта `ABSENT → inert, PRESENT → байты фолдятся`), версия её пакета сдвинется у ВСЕХ её книг, включая те, чей ТЕКСТ не изменился ни на байт — например текстовые книги, для которых новая возможность недостижима по построению. ⚠ **Это ЛОЖНАЯ перепокупка, то есть безопасная сторона ошибки: она видна в проекции согласия и не портит текст.** Но это деньги, и с каждой новой парой их будет больше. ⛔ **Направление лечения названо советчиком и НЕ спроектировано:** расширить забор на «wire-нейтральные оси» — ход, при котором отличаются только оси, чьё действие целиком лежит в отправляемых сообщениях (нарезка · встроенные данные · нормализация · пакет пары), И при этом контент-хеш совпал; вердикт-несущие оси (классификатор · дешёвые гейты · экран цели) остаются «прочим». ⚠ Граница «ось лежит целиком в сообщениях» доказывается ПО КАЖДОЙ оси отдельно — это дизайн, а не правка условия. ⛔ **И почему это НЕ делается перед прогоном:** `repin.go` есть денежно-критичный путь, а ошибка в заборе даёт исход, противоположный нынешнему — тихую НЕ-перепокупку там, где заплатить надо. Прогон идёт с нынешним поведением, цена названа вслух. | бэкенд | скоро (после прогона; до него — ТОЛЬКО назвать цену в акте, не трогать) | забор ре-пина различает wire-нейтральный ход от вердикт-несущего, граница каждой оси доказана отдельно, и пин краснеет на попытке пропустить вердикт-несущую ось как нейтральную | разбор советчика 18.09 при ратификации условного фолда маркера разметки; несущие утверждения пере-сняты оркестратором (контент-гард `backend/internal/pipeline/stagerun.go:92`=`cs.ContentHash == contentHash`; образец — коммит `2f91b04`, 207 строк в нарезчик при нетронутой константе версии) | | 504 | ⛔ **ТАЙМИНГОЗАВИСИМЫЙ ПИН В `internal/llm` КРАСИТ ЧУЖИЕ ЛЕНДИНГИ — ДВА НЕЗАВИСИМЫХ СВИДЕТЕЛЯ ЗА ОДНУ СМЕНУ.** Тест `TestARefusalIsNotAPurchaseEvenWhenTheReplyOutrunsTheWrite` (подтест «тело ещё писалось, когда пришёл отказ») упал у ДВУХ разных сессий, на ДВУХ разных деревьях. ⚠ **ИСПР. ТУТ ЖЕ, ДО ЛЕНДИНГА РЯДА: «ни одна сессия пакет не трогала» — НЕВЕРНО, и поймал это мой же прибор.** Файл упавшего теста (`backend/internal/llm/attemptcut_test.go`) действительно не тронут ни одним коммитом смены (строк диффа 0), но ПАКЕТ тронут: `9defda4` добавил **19 строк** в `backend/internal/llm/httpllm.go` — это работа второй сессии по имени для исчерпания средств провайдера. ⇒ у первого свидетеля дерево пакета не касалось вовсе, у второго — касалось соседнего файла того же пакета, и потому **«дефект не её» НЕ УСТАНОВЛЕНО**: гипотеза о взаимодействии её правки с таймингом остаётся открытой, пока не сойдётся замер частоты в двух деревьях вперемежку. **Первый свидетель 18.09:** батарея `final8` сессии английской пары — текст падения говорит не о предмете, а о своей ПОСЫЛКЕ: «premise: the provider was connected to 3 time(s) … write: connection reset by peer» и «the client came back with a STATUS, so this run never reached the delivery question». **Второй свидетель 18.09:** гейт сессии достижимости пар-данных, причём упал ВТОРОЙ проход цели — тот, что собирает скипы без гонок, — тогда как `build vet fmt lint test` прошли и полнота сверена списком. ⭐ **Конструкция теста ХОРОША и это надо сказать прежде дефекта:** он не позеленел молча, не дойдя до предмета, а объявил вслух, что до вопроса о доставке не дошёл. Именно поэтому его красное есть информация, а не шум. **Дефект в другом:** он чувствителен к нагрузке — локальной HTTP-фикстуре сбрасывают соединение, — и тогда он красит ЧУЖОЙ лендинг, заставляя зону доказывать невиновность. Изолированно зелен 8 из 8 у обеих сессий. ⚠ **Разделить «нагрузка» и «дефект дерева» можно только правильным прибором:** чередующиеся полные проходы в своём дереве и в развёрнутом срезе `HEAD`, счёт частоты с обеих сторон; одинаковая частота = не твоё. Вторая сессия этот замер ведёт, числа придут со сдачей. ⛔ **И родня, из-за которой ряд заводится отдельным:** это ВТОРОЙ такой пин за двое суток (первый — ряд **497**, квадратичность), то есть класс, а не случай: **пин, утверждающий отношение или порядок событий, на общей машине меряет нагрузку вместе с предметом**. | бэкенд | скоро (не блокер прогона: предмет пина к пути прогона не относится, но красит лендинги) | падение различает нагрузку от предмета САМО — либо фикстура перестаёт зависеть от того, кто ещё работает на машине, либо тест объявляет исход «не измерено» вместо красного; предъявить частотой падений в двух деревьях вперемежку, а не одиночным прогоном | два независимых свидетеля 18.09 — батареи `textmachine-main-c5` и `textmachine-main-c8`. ⭐ **ЗАКРЫТО ПО ПРИЧИНЕ 18.09 ЗАМЕРОМ ЗОНЫ, И КОНТРОЛЬ ВЗЯТ ПРАВИЛЬНЫЙ, А НЕ УДОБНЫЙ:** сравнение под РАВНОЙ нагрузкой против дерева `9defda4^`, где правки зоны нет вовсе, дало **2 падения из 30 в контрольном дереве против 0 из 30 в правленом** ⇒ моя гипотеза о взаимодействии её правки с таймингом ОПРОВЕРГНУТА, и опровергнута в сторону, невыгодную опровергающему. **Механизм понят:** тест шлёт 11 МБ тела, которого сервер не читает, отдаёт обрывок статус-строки и спит ФИКСИРОВАННЫЕ 200 мс перед сбросом соединения — под нагрузкой планировщик не успевает прочитать обрывок. Предикат, добавленный паком в тот же пакет, внутри него не зовётся НИ РАЗУ (0 вызовов; единственный вызов идёт из `backend/internal/pipeline/stagerun.go`). ⇒ предмет ряда — **фиксированный сон против планировщика**, а не чья-либо правка. | diff --git a/docs/NEAR_TERM_PLAN.md b/docs/NEAR_TERM_PLAN.md index ac19db4f..b3892f78 100644 --- a/docs/NEAR_TERM_PLAN.md +++ b/docs/NEAR_TERM_PLAN.md @@ -50,12 +50,13 @@ | 2 | **платформа** | правда у двери: `PD-455` · `PD-448` (разбор) · `PD-162` | $0 | ✅ **ЗАКРЫТ АКТОМ `D39.246`** с дофиксом по двум находкам приёмки | | 3 | ~~полигон~~ | **прогон A**: настоящая книга до ФАЙЛА, платный провайдер | **факт $0.419424** | ✅ **ЗАКРЫТ АКТОМ `D39.247`**; строка 16 закрыта замером; ⚠ зона ВНЕ СКОУПА с 11.09 | | 4 | **бэкенд** | ⛔ **КОНСИСТЕНТНОСТЬ, КОТОРУЮ МОЖНО ПРЕДЪЯВИТЬ**: ряды **406** · **407** · **408** · **409**, плюс купленные прогоном **417** (закон банка не виден в тексте) и **419** (стеммер: 11 из 18 промахов — ложные) | пак, почти весь $0 | ✅ **ЗАКРЫТ АКТОМ `D39.249`** с дофиксом | -| 5 | **бэкенд** | «ВЫДАЧА, КОТОРУЮ ВИДИТ ЧИТАТЕЛЬ» — ⛔ **РАЗОБРАН 11.09 ЧТЕНИЕМ РЯДОВ И РАЗВЕДЁН НА ДВА ПАКА, один ряд закрыт замером.** **(а) `291` ЗАКРЫТ актом `D39.255`** — промт в `archive/prompts/BACKEND_BOUGHT_MEANS_DELIVERED_SESSION_PROMPT.md` с баннером-исходом, решено владельцем (`D39.204` с «Эрратой 15.09-а»), дефект был жив на 11.09 (возврат ошибки из цикла попыток до `UpsertChunkStatus`, `backend/internal/pipeline/stagerun.go`); акт ОДИН с платформенной половиной (⚠ испр. 15.09: платформенная половина пуста по замеру сессии, отдельного промта нет). **(б) `307` ЗАКРЫТ, а не заказан:** честная форма ПОСТРОЕНА и запинена коммитом `6ceb133` — `runOrderedChapters = (case when r.ordered_units is not null then null else r.ceiling_chapters end)`, плюс `TestACharacterOrdersVolumeIsPublishedInTheUnitItWasSoldIn`; ряд снят с таблицы. Заказать его значило бы заказать готовое — мой повторяющийся класс. **(в) `283` + `284` + `201` — СЛЕДУЮЩИЙ пак «структура и заголовки», и он идёт ПОСЛЕ прогона B:** 283 требует единственного окна пере-снапшота, а пере-снапшот двигает НАРЕЗКУ ⇒ единицы A и B станут несравнимыми, и B ответит на другой вопрос (поправка старшего коллеги, принята). У 284 сверх того нет слова владельца о ПОДПИСИ стадии | пак, $0 | ✅ (а) **ПРИНЯТ 16.09 актом `D39.255`**, лендинг `af88680` (29 путей, $0): закрыты ряды **291** и **379** (379 — ЗАМЕРОМ, мутант 8/8 против 7/8 в ряду), остаток — 375 · 232 · 453–456. Пак пережил ПОТЕРЮ сессии b1 и доведён `textmachine-main-b1` разделом ред. 5; конструкция пере-решена владельцем 11.09: стандартная остановка, не флаг (эррата 15.09-а к `D39.204`). **Слот бэкенда СВОБОДЕН** · (б) закрыт · (в) прогон B принят (`D39.252`), заперт теперь слотом и порядком — см. пункт 10 | +| 5 | **бэкенд** | «ВЫДАЧА, КОТОРУЮ ВИДИТ ЧИТАТЕЛЬ» — ⛔ **РАЗОБРАН 11.09 ЧТЕНИЕМ РЯДОВ И РАЗВЕДЁН НА ДВА ПАКА, один ряд закрыт замером.** **(а) `291` ЗАКРЫТ актом `D39.255`** — промт в `archive/prompts/BACKEND_BOUGHT_MEANS_DELIVERED_SESSION_PROMPT.md` с баннером-исходом, решено владельцем (`D39.204` с «Эрратой 15.09-а»), дефект был жив на 11.09 (возврат ошибки из цикла попыток до `UpsertChunkStatus`, `backend/internal/pipeline/stagerun.go`); акт ОДИН с платформенной половиной (⚠ испр. 15.09: платформенная половина пуста по замеру сессии, отдельного промта нет). **(б) `307` ЗАКРЫТ, а не заказан:** честная форма ПОСТРОЕНА и запинена коммитом `6ceb133` — `runOrderedChapters = (case when r.ordered_units is not null then null else r.ceiling_chapters end)`, плюс `TestACharacterOrdersVolumeIsPublishedInTheUnitItWasSoldIn`; ряд снят с таблицы. Заказать его значило бы заказать готовое — мой повторяющийся класс. ⛔ **(в) `283` + `284` + `201` — РАЗБЛОКИРОВАН 18.09, И ЗАПРЕТ БЫЛ СРОЧНЫМ, А НЕ ВЕЧНЫМ; прежняя редакция ниже, как история замысла.** Условие звучало «идёт ПОСЛЕ прогона B», и **B куплен и принят актом `D39.252`** ⇒ условие ИСПОЛНИЛОСЬ, а не отпало. ⛔ И довод перевернулся знаком: пере-снапшот запрещали ради сравнимости единиц A и B, **оба прогона теперь в прошлом**, а следующий платный прогон ещё НЕ начат ⇒ сегодня единственное окно, в котором нарезку можно двигать бесплатно, и **закрывает его СТАРТ холодного прогона**, а не чей-то запрет. ⇒ пере-кроящие ряды едут ПЕРЕД прогоном или не едут вовсе до следующего окна. У 284 сверх того нет слова владельца о ПОДПИСИ стадии — это по-прежнему верно и держит 284 отдельно от 283. ⚠ Прежняя редакция: «СЛЕДУЮЩИЙ пак, идёт ПОСЛЕ прогона B: 283 требует единственного окна пере-снапшота, а пере-снапшот двигает НАРЕЗКУ ⇒ единицы A и B станут несравнимыми» | пак, $0 | ✅ (а) **ПРИНЯТ 16.09 актом `D39.255`**, лендинг `af88680` (29 путей, $0): закрыты ряды **291** и **379** (379 — ЗАМЕРОМ, мутант 8/8 против 7/8 в ряду), остаток — 375 · 232 · 453–456. Пак пережил ПОТЕРЮ сессии b1 и доведён `textmachine-main-b1` разделом ред. 5; конструкция пере-решена владельцем 11.09: стандартная остановка, не флаг (эррата 15.09-а к `D39.204`). **Слот бэкенда СВОБОДЕН** · (б) закрыт · (в) ⭐ **РАЗБЛОКИРОВАН 18.09** покупкой прогона B (`D39.252`): запрет был про сравнимость A и B, оба в прошлом ⇒ окно пере-кроя ОТКРЫТО и закроется стартом холодного прогона. Ведёт пункт **11** | | 6 | **фронт** | поверхность показа | пак | разморозка + пункты 1–5 | | 7 | ~~полигон~~ | ⛔ **ЗОНА ВНЕ СКОУПА — слово владельца 11.09**; четыре промта уведены в `archive/prompts/` с баннерами | — | снято | | 8 | **бэкенд/деньги** | ⛔ **«ПАДЕНИЕ, КОТОРОЕ ВИДНО»** — четверть COGS в одном механизме (**415**), слепые приборы отказа (**414**, **422**), молчащая подстановка цены. ⚠ Пин цены **413** из пака ВЫНУТ: это данные и отдельное решение | пак, $0 | ✅ **ЗАКРЫТ АКТОМ `D39.251`** (испр. 15.09; дальше — запись 11.09) · ✍️ **НАПИСАН 11.09** — `BACKEND_FAILURE_YOU_CAN_SEE_SESSION_PROMPT.md`; выдаётся СВЕЖЕЙ сессии сразу по закрытии 4 ⛔ **КРИТЕРИЙ ПРИЁМКИ ПАКА — МЕХАНИЗМ, А НЕ ПРОПОРЦИЯ** (поправка старшего коллеги 11.09): лекарство есть распространение ратифицированного образца `D2` п.3 на вторую причину, и оно верно при 25 % и при 5 % — пропорция задаёт очерёдность, не форму. ⇒ судить по строкам «ни одного удвоения без вердикта о вырождении; каждая выброшенная попытка — строкой леджера с причиной», а не по «с 25.4 % до X». Значит прогон B пак не гейтит и паком не гейтится.| | 9 | **платформа+бэкенд** | ⭐ **ХОЛОДНЫЙ ПРОГОН B — платформа → бэкенд → файл, ВТОРОЙ раз.** Уточнение владельца 11.09: спрашивая «перепрогоны нужны», он имел в виду именно сквозной прогон, а не пере-запуск тестов. Покупает ЧЕТЫРЕ вещи, которых нет ни у кого: **(1)** миграция **v17** (`wave_selection`) пака консистентности ни разу не шла на живом прогоне — только в тестах; **(2)** прибор консистентности впервые даст числа с ЖИВОГО прогона, а не с пере-скана сохранённой базы прогона A — сегодня все `I1`/`I2` получены повторным чтением одних и тех же данных; **(3)** платформенный пак (идемпотентный резюм, терминальное состояние) проверяется сквозь, а не юнитами; **(4)** ⛔ **вторая точка по денежной дыре, и она нужна по норме, а не для красоты** — весь довод «четверть денег купила пустоту» стоит на ЧЕТЫРЁХ одиночных розыгрышах, а квирки §3д прямо говорят: смета DeepSeek с одиночного вызова может ошибиться на порядок, сметы строятся на ПОВТОРАХ. ⇒ у числа 25.4 % есть знак и нет величины, пока прогон не повторён. **Цена ≈$0.42 по образцу прогона A, машинный кап ≈$2.5.** ⛔ **ПРЕ-РЕГИСТРАЦИЯ ЗНАМЕНАТЕЛЯ, иначе B ответит числом на другой вопрос** (поправка старшего коллеги 11.09): B — ЕЩЁ ОДИН одиночный прогон, и две точки распределением не станут. Настоящая ценность B не «вторая точка к 25.4 %», а `request_log` ВСЕХ единиц прогона ⇒ **доля выброшенных первых попыток ПО ЕДИНИЦАМ, а не по вызовам.** Это и пре-регистрируется. ⚠ И идёт B **ПАРАЛЛЕЛЬНО** паку о падениях, а не после: они в РАЗНЫХ слотах (бэкенд против платформы), и правило «один промт на зону» их не сталкивает | ≈$0.42 | ✅ **ЗАКРЫТ АКТОМ `D39.252`**, факт $0.396657 | | 10 | **бэкенд** | ✅ **ЗАКРЫТ АКТОМ `D39.266`** 17.09 (`d25e418`, 32 пути, $0): носитель — таблица `bank_basis`, миграция v19, аддитивная; ряд **490** закрыт по трём условиям, **130** получил ТРЕТИЙ исход (замысел достигнут другим механизмом, стоп-решение остаётся за владельцем), два отказа с замером, заведён **496**. Числа приёмки: кампания **315/315 поймано, выживших 0**; M1 — **67 из 69** и **64 из 66** обслужено из памяти. Прежняя формулировка предмета: ⛔ **БАНК: РЕШЁННОЕ ОСТАЁТСЯ РЕШЁННЫМ** — предмет пере-определён проверкой 15.09. Пак 12.09 «в банк по разнобою» (`archive/prompts/BACKEND_WHAT_THE_BANK_IS_MADE_OF_SESSION_PROMPT.md`) снят баннером: все термы со `spread ≥ 2` уже в банке (A 9 из 9, B 8 из 8). Настоящий дефект приоритета №1 — пере-решение банка терминологом: на подписи замерено (у неподписанных строк сменились передачи A 12 из 69, B 14 из 66), на каждой следующей покупке глав выведено из кода — отгруженные главы по порядку слотов остаются со старыми передачами (`backend/internal/pipeline/volume.go`, греп `DELIVERY BEFORE REWORK`). Ряды 130 · 330 · 438 · 440 | $0 + центы перекупки банк-ролей | ⛔ **ПРОЕКТ ОРКЕСТРАТОРА ОТОЗВАН 15.09.** «Банк — журнал решений с окнами» (две редакции Fable 5) расходился с 12 пунктами решённого, замеренного и этого же плана и опирался примерно на десятую часть относящегося; улики — `archive/reports/BANK_CONSILIUM_INPUTS_2026-09-15/`. ✅ **КОНСИЛИУМ ОТРАБОТАЛ, акт `D39.253` (16.09).** Итог — `research/35-bank-memory-consilium.md`: банк как решение по уликам с пятью событиями пересмотра, N-1 на построенном фильтре, N-3 на сборке вида, ряды бэклога 441–450. ✅ **СЛОВО ВЛАДЕЛЬЦА ПОЛУЧЕНО 16.09** (`D39.254`): держать решение между покупками — да · при невозможной безродовой форме — перестроить фразу, иначе «как лучше читается» · богаче контекст — да, меру решает замер M4 · голос и ты↔вы — строить. ⚠ **Вопрос об отказе терминолога ПЕРЕ-ОПРЕДЕЛЁН владельцем:** у банк-ролей нет ни ретрая, ни фоллбека (ряды 435, 438), и он считает это дырой ⇒ заведён ряд 451 «умный участок в точке банка», ряд 452 — голос. ✅ **ГРАНИЦЫ ДАНЫ ВЛАДЕЛЬЦЕМ 16.09** — «в границах ратифицированного», и слот бэкенда освобождён приёмкой `D39.255`. ✅ **ПАК 1 ПРИНЯТ 16.09 актом `D39.257`** (29 путей, $0; посылка В1 закрыта замером — 25 из 26 при идентичном входе). Промт написан был 16.09 — `BACKEND_BANK_ZERO_LAYER_SESSION_PROMPT.md`, пак $0 (громкий отказ при цели без инъекционных текстов до первой траты · отказ роли перестаёт ехать законом · предикат «спорный» как ДВА предиката с заданными знаменателями · носитель посылки «новой улики не было»); круг опровергателя пройден. ✅ **ВЫДАН и ПРИНЯТ 16.09** — акт `D39.257`. Вопросы владельцу, в том числе ряд 130 (`research/34` §4 п.4), ставит его итог; он же решает порядок относительно 5(в). Довод «перекрой глав без якоря пере-решил бы банк платной книги» остаётся входом ✅ **ПЕРЕНОС БАНКА РЕШЁН ВЛАДЕЛЬЦЕМ 16.09 — акт `D39.256`:** в КНИГУ-ПРОДОЛЖЕНИЕ едут ПОДПИСАННЫЕ строки ПЛЮС строки, РЕШЁННЫЕ ДВИЖКОМ; стройка ДВУХЗОННАЯ и ещё не начата — ряд **461**. ⚠ **Эррата 16.09-б:** формулировка «причина смен передачи — якорь» в `D39.256` и `D39.257` СИЛЬНЕЕ замера — измерено лишь отсутствие новой улики во ВХОДЕ, причина остаётся гипотезой, гейт — ряд **466**. Прочее живое банка: ряды **462** · **465**. ⭐ **ЗАКАЗАН 17.09: промт «РЕШЁННОЕ НЕ ПЕРЕ-СПРАШИВАЕТСЯ» ВЫДАН** сессии `textmachine-main-57` (выдача №14, `docs/BACKEND_SETTLED_STAYS_SETTLED_SESSION_PROMPT.md`, $0). Строит базис решённого как ИСТОЧНИК ОТВЕТОВ (ряд 130) и стража разрыва окон (ряд 490); замер M1 идёт ПЕРВЫМ блоком, и носитель не пишется, пока оркестратор не принял форму предиката по числам. ⚠ **Состав сузился против проекта консилиума, и это измерено, а не решено вкусом:** N-4 и Б-5 ПОСТРОЕНЫ паком `D39.257`; N-6 гейчен разморозкой фронта (ряды **214** · **221**); Б-2 протух — токен «stops loudly» живёт только в тесте; N-3 и стратифицированный отбор вынесены НАРУЖУ, каждый со своим замером. Промт прошёл два рубежа (механическая сверка 13 блоков и субагент-опровергатель: 12 находок, 9 денежных, все внесены) и всё равно был исправлен релеем после выдачи — материал замера указывал на другую книгу. | +| 11 | **бэкенд** | ⭐ **ОКНО ПЕРЕ-КРОЯ — ВСЁ, ЧТО ДВИГАЕТ НАРЕЗКУ И ДАННЫЕ ПАРЫ, ЕДЕТ ДО СТАРТА ХОЛОДНОГО ПРОГОНА.** Открыто 18.09 покупкой прогона B, закроется стартом прогона — см. 5(в). Состав: **283** + **303** (один шов с двух сторон: грамматика не участвует там, где режут) · **201** (движковое «Глава N» внутри текста) · **410** (голос построен сквозь и выключен двумя тумблерами, конфиг-ключа нет) · вынос свёрток нормализации источника из ядра в данные пары. ⛔ **Порядок задан владельцем 18.09, дословно: «цель: не бежать поскорее приступить к холодному прогону а подготовить бэкенд так что б этот холодный прогон исполнить максимально правильно. Сколько паков и бэклога нам для этого нужно закрыть не очень важно. Халтурить не надо, подгонять тоже ничего не надо, спиливаем долг из бэкенда, реализуем актульный, нужный чистый архитектурно код».** ⇒ число паков перестало быть ограничением, и «успеть к прогону» перестало быть доводом за срез | паки, $0 | ✍️ **ПАК 1 НАПИСАН 18.09** — `BACKEND_CHAPTER_STRUCTURE_SESSION_PROMPT.md` (границы глав; корень найден подсказкой владельца — см. «СОСТОЯНИЕ НА 18.09»). Не выдан: идёт второй рубеж | ⛔ **ПОЧЕМУ 4 ВСТАЛ ПЕРЕД 5 (решение 11.09 по мерилу владельца).** Мерило — «качественный КОНСИСТЕНТНЫЙ перевод длинных книг». Аудит банка 11.09 показал, что **книжного вопроса о консистентности не задаёт ни один @@ -65,6 +66,42 @@ переиспользуют построенное; ряд 408 — вообще ДАННЫЕ, а не Go. Носитель разбора — `docs/research/34-memory-bank-quality-audit.md`, акт — `D39.243`. +## СОСТОЯНИЕ НА 18.09 — приоритет пере-определён владельцем, и корень структуры глав найден его же подсказкой + +⛔ **РЕШЕНИЕ ВЛАДЕЛЬЦА 18.09 СНИМАЕТ СРОК КАК ОГРАНИЧЕНИЕ.** Дословно: «цель: не бежать поскорее приступить к +холодному прогону а подготовить бэкенд так что б этот холодный прогон исполнить максимально правильно. +Сколько паков и бэклога нам для этого нужно закрыть не очень важно. Халтурить не надо, подгонять тоже ничего +не надо, спиливаем долг из бэкенда, реализуем актульный, нужный чистый архитектурно код». ⇒ **довод «это +успеется после прогона» больше не действует ни для одного ряда, который прогон трогает**, а «сколько паков» +перестало быть величиной, которую надо минимизировать. Второе слово того же дня: «прежде чем что то принимать +проверяй это по коду\документации», «просии сессии по возможности пилить алгоритмы в бэкенд которые будут +отвечать нашим стандартам проекта». + +⭐ **КОРЕНЬ СТРУКТУРЫ ГЛАВ НАЙДЕН, И НАШЁЛ ЕГО ВЛАДЕЛЕЦ ОДНОЙ ФРАЗОЙ.** Я дважды поставил предмет неверно — +сперва обошёл его срезом книги, потом искал эвристику против мусорных целей навигации, и оба раза это был +поиск лекарства от симптома. Владелец сказал: «у нас есть статический код который смотрит глава ли это и как +она названа, там как то это все должно склеиваться». **Замер подтвердил дословно.** Диспетчер ингеста получает +грамматику источника и отдаёт её только одному из двух путей: +`backend/internal/chunk/ingest.go:243`=`func ingestTXT(p, encoding, sourceLang string, st *lang.SourceStructure)` +берёт `st`, а `backend/internal/chunk/ingest.go:678`=`func ingestEPUB(p string, im *lang.InlineMarkup)` не +берёт её вовсе. ⇒ **механизм, умеющий сказать «это глава и вот её имя», построен и работает на одном пути из +двух**; на EPUB границу единолично назначает навигация издателя, и когда она врёт — а в книге прогона 60 целей +из 71 имеют тело, байт-в-байт равное собственному заголовку, — её никто не поправляет. + +**Следствие для бэклога, и оно сокращает работу, а не добавляет:** ряды **283** и **303** — один и тот же шов +с двух сторон. 303 говорит «чанкер безъюнитную грамматику уже умеет, ингест по ней не режет», 283 — «ридер +делает главу из каждого документа». Оба лечатся тем, что грамматика начинает участвовать ТАМ, ГДЕ РЕЖУТ, и ни +один не требует ни порога в знаках, ни ветки по языку. ⚠ Ряд **302** (несколько глав в ОДНОМ документе) — +ОБРАТНЫЙ предмет и в это окно намеренно не берётся. + +**Дизайн `backend/docs/CHAPTER_STRUCTURE_DESIGN.md` остаётся ПРЕДЛОЖЕНИЕМ** (четыре адверсариальных круга без +сходимости, акт `D39.245` закрыл его правилом остановки, а не согласием). Предметная часть его выдержала, +механика исполнения — нет; пак 18.09 берёт предметную часть и ставит механику заново от найденного шва. + +**Готовность к холодному прогону ратифицирована актом `D39.269`** — со списком того, чего акт НЕ утверждает, и +этот список теперь и есть содержание окна пере-кроя (строка 11 горизонта). ⚠ **Пак холодного прогона написан и +закоммичен, но НЕ ВЫДАН намеренно:** порядок задан решением владельца выше — сперва долг, потом прогон. + ## СОСТОЯНИЕ НА 17.09 — что выяснено кругом 16–17.09 и что из этого следует ⛔ **ЭТАП ПО БАНКУ НАЗВАН ЧЕСТНО: спроектировано всё, ПОСТРОЕН ОДИН механизм из семи.** Консилиум сдан и принят (`D39.253`), @@ -283,7 +320,7 @@ API не было: 04.09 упёрлось в потолок (`PD-440`, с тех - ✅ **ОКНО ПЕРЕКРОЯ ОТКРЫТО, ПЕРЕКУПКА РАЗРЕШЕНА** (слово 17.09, дословно: «Да, ничего. Можно перекупить, перезаписать что тебе нужно и выполнить все тесты\актуализировать все»). ⇒ **санкция на правку ВСТРОЕННЫХ данных ядра и на ре-снапшот купленной книги.** Цена названа и принята: файлы `backend/internal/lang/data/` встроены `go:embed`, - `lang.EmbeddedVersion()` хеширует их целиком (`backend/internal/lang/embedded.go:79`=`hashEmbeddedFiles`), хеш двигает + `lang.EmbeddedVersion()` хеширует их целиком (`backend/internal/lang/embedded.go:80`=`hashEmbeddedFiles(embeddedDataFiles())`), хеш двигает тег кроя и ключ манифеста ⇒ у купленной книги стираются `unit_resolutions` платформы и пере-покупается нарезка. ⛔ **Окно ОДНО и закрывается первым же продолжением книги** — пока платная книга одна и тома 2 нет, все правки встроенных данных идут ОДНИМ заходом и платят ре-снапшотом ОДНАЖДЫ. Состав окна на 17.09: родовая директива diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md index e3a07acb..fc2c019b 100644 --- a/docs/PROGRESS.md +++ b/docs/PROGRESS.md @@ -2537,7 +2537,7 @@ decision»). 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/` не читается). Вывод держится; число было не моё. +**Проверено и дефекта НЕ найдено** (называю, чтобы был виден охват): путь подписи банка `bank-apply` новым отказом НЕ задет — он открывает стор напрямую (`backend/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 промта): что каждый механизм делает с ЧУЖИМИ деньгами, если сработает ошибочно diff --git a/docs/architecture/05-decisions-log.md b/docs/architecture/05-decisions-log.md index 3e9412de..be9ca550 100644 --- a/docs/architecture/05-decisions-log.md +++ b/docs/architecture/05-decisions-log.md @@ -33,12 +33,12 @@ > ⚠ **Эррата 20.08 (D39.153 п.7б):** D39.144 п.2 атрибутирует пер-термный гейт полноты банка «изобретению КОНТРАКТНОЙ линии (Ф-14 → спека → 0.3.0)» — верно про ГЕЙТ и **неверно про ФОРМУЛУ**. Формула «стоп очищается, когда каждый терм промоутнут ИЛИ отклонён» родилась 19.07 В ДВИЖКЕ как лечение ливлока R1-FL-B (отклонённый терм переспрашивался каждый прогон — тело D39.19, слайс `../archive/architecture/05-decisions-D39-arch-reset.md:22`) и живёт там до сих пор (`backend/internal/pipeline/mining.go:80-82,243`); контрактная линия 04.08 переписала её дословно и вывела из неё ЭКРАННЫЙ гейт — счётчик «решено N из M» и запрет продолжить (коммит `16e20e5`, `frontend/docs/API_CONTRACT_INPUT.md:258-264`). **Следствие, из-за которого эррата несущая:** снимая гейт, D39.144 адресовала только контракт, поэтому движковая половина осталась БЕЗ явной отмены — она сегодня ОБОЙДЕНА платформой (флаг не передаётся на resume), а не устранена; носитель — строка 191(б), развилка — строка 203(з). > ⚠ **Эррата 27.08 (D39.158 п.7):** D39.153 п.7б объявляет «ОСТАТКА-РАТИФИКАЦИИ НЕТ… гейт проверяет полноту ФАЙЛА решений, а не подписей, и ОДИН файл со всем банком его снимает — конфликта с моделью владельца нет». Читать так: диспозиция отвечала на вопрос «снимает ли гейт один файл» (снимает) и верифицировала СОСТАВНОЕ поведение — платформа снимает флаг, движок уходит по авто-ветке. Вопрос «работает ли флажок БЕЗ обхода» ею не закрывался, и заказанное той же строкой 191(б) «ослабить границу самой паузы» исполнено не было. Исполнено D39.158: движковая половина УСТРАНЕНА, не обойдена. > ⚠ **Эррата 27.08-б (D39.158, страница `18-bank-ontology.md`):** названный там класс дефекта «проекция без потребителя и без якоря свежести» на момент ратификации имел ОДИН ярус и не судил носитель с ДВУМЯ писателями и нулём читателей. Дописан второй ярус: расхождение писателей ничем не судится, пока читателя нет, а в день его появления СТАНЕТ семантикой, разрешаемой задним числом по накопленной истории. Найдено платформенной сессией при вычитке приёмки D39.159 (живой член — `PD-396`); правило «у источника РОВНО один писатель» с этого дня читается в обе стороны. -> ⚠ **Эррата 27.08-в (D39.158 п.1):** «движок исполняет продуктовую модель сам» сказано без ратифицированной ОГОВОРКИ — правка ОТДЕЛЬНОГО термина через дверь доступна только для mined-термов; правка СИД-терма дверью отклоняется по имени (`internal/membank/decisions.go:359`=`Scoped to APPROVE`), потому что это перенос базового снапшота и пере-оплата черновой волны — другое решение (щель ратифицирована, строка бэклога 192). Ещё три места, где модель шире кода, названы строками: окно глав одним решением не правится (named-узость v1) · банк-экспорт на стопе пуст (224) · «полный останов» — это граница ПЕРЕД редакторской волной, черновая довершается (S16). Найдено вычиткой старшего при ревью D39.159. +> ⚠ **Эррата 27.08-в (D39.158 п.1):** «движок исполняет продуктовую модель сам» сказано без ратифицированной ОГОВОРКИ — правка ОТДЕЛЬНОГО термина через дверь доступна только для mined-термов; правка СИД-терма дверью отклоняется по имени (`backend/internal/membank/decisions.go:359`=`Scoped to APPROVE`), потому что это перенос базового снапшота и пере-оплата черновой волны — другое решение (щель ратифицирована, строка бэклога 192). Ещё три места, где модель шире кода, названы строками: окно глав одним решением не правится (named-узость v1) · банк-экспорт на стопе пуст (224) · «полный останов» — это граница ПЕРЕД редакторской волной, черновая довершается (S16). Найдено вычиткой старшего при ревью D39.159. > ⚠ **Эррата 27.08-г (D39.159 п.8):** отказ от правки `n != shape` СТОИТ, но обоснование было шире истины — «краснит семь ЗАКОННЫХ строк» неверно для двух из них. `PD-99` несла корректно markdown-экранированные черты (виноват был парсер, не строка), а `PD-197` — сырую черту в регексе, которая молча сдвигала ВЕС, потому что он читался с конца, а от конца далеко. Названный там остаточный риск ПОСТРОЕН 27.08 на эмпирике зоны (три молчаливых случая за двое суток): парсер уважает экранирование · вес регистра читается с НАЧАЛА · гейт `tail_vocab` судит словарь хвоста. Проверено подсадкой; числа не сдвинулись. Строка `PD-398` остаётся открытой на отсутствие автоматического пина у самого гейта. -> ⚠ **Эррата 27.08-д (D39.159 п.7) — норма §3 п.8 применена к СОБСТВЕННОМУ бэклогу, три строки переsуждены.** Свип грепом по путям лендинга `d1eb8a9` нашёл, что лекарство трёх строк уже в дереве. **212 ЗАКРЫТА и снята с таблицы:** голый `yaml.Unmarshal` заменён строгим `seed.DecodeFile` (`internal/membank/memseed.go:51`=`whether the document it is ABOUT to write would load`, код называет строку по номеру), пин двойной — `internal/seed/decode_test.go:16`=`_, err := DecodeFile(` и `internal/membank/seedlint_test.go:39`=`misspelled field name`. **218 ЗАКРЫТА и снята:** три тест-хелпера снесены, `miner_parity_test.go:35` говорит «the old $HOME/books address is dead». **199 СУЖЕНА:** движковая половина цепи доставки правок банка ПОСТРОЕНА, открыт только платформенный конец (пункт 2в очереди) — прежняя формулировка «канал НЕ построен» отправляла бы следующий пак строить построенное. Бэклог 177 → 175. ⚠ Норма окупилась на своём авторе в тот же день, что и на чужом. +> ⚠ **Эррата 27.08-д (D39.159 п.7) — норма §3 п.8 применена к СОБСТВЕННОМУ бэклогу, три строки переsуждены.** Свип грепом по путям лендинга `d1eb8a9` нашёл, что лекарство трёх строк уже в дереве. **212 ЗАКРЫТА и снята с таблицы:** голый `yaml.Unmarshal` заменён строгим `seed.DecodeFile` (`backend/internal/membank/memseed.go:51`=`whether the document it is ABOUT to write would load`, код называет строку по номеру), пин двойной — `backend/internal/seed/decode_test.go:16`=`_, err := DecodeFile(` и `backend/internal/membank/seedlint_test.go:39`=`misspelled field name`. **218 ЗАКРЫТА и снята:** три тест-хелпера снесены, `miner_parity_test.go:35` говорит «the old $HOME/books address is dead». **199 СУЖЕНА:** движковая половина цепи доставки правок банка ПОСТРОЕНА, открыт только платформенный конец (пункт 2в очереди) — прежняя формулировка «канал НЕ построен» отправляла бы следующий пак строить построенное. Бэклог 177 → 175. ⚠ Норма окупилась на своём авторе в тот же день, что и на чужом. > ⚠ **Эррата 27.08-е (D39.159 п.8, финал): `PD-398` ЗАКРЫТА — у построенного гейта появился пин.** `selftest_tail_vocab()` гоняется на каждом `--check`, четыре утверждения, проверен ПОСАДКОЙ трёх мутаций самого гейта (все три пойманы, базовая линия молчит). ⚠ Первая редакция пина молчала на одной из трёх: утверждение про вес проверяло `cells()`, а мутация меняет то, чем пользуется `register()`. Пин, проверенный одним прогоном вместо посадки, — ровно тот класс, который эта строка описывает; поймано только потому, что посадку сделал. Регистр 96 → 95 открытых. > ⚠ **Эррата 27.08-ж (D39.160 п.2) — ошибка ОРКЕСТРАТОРА, найденная исполнителем пака.** Нота утверждала, что после сноса отменённой двери «канон и деплой СОВПАДУТ точно», а промт минора (§3.2-бис) — что счётчики `pending_decisions`/`complete` «навсегда нули». **Верно по ПУТЯМ, неверно по ПОЛЯМ:** проекция `GET /bank` продолжает их слать, и это не нули — `bankCountsTx` (`platform/internal/pgstore/readmodel.go:330`) считает `proposed`-строки, о чём говорит её собственный комментарий. Клиент 0.5.0 лишние поля игнорирует, но аллоулист-норма нарушена до монтажа (2в). Носитель — `PD-399`. ⚠ Контрактная сессия принесла это ПИНГОМ по §11 промта, вместо того чтобы тихо подогнать работу под неверную посылку; это и есть поведение, которого норма требует. -> ⚠ **Эррата 27.08-з (D39.156, состав пункта 2в): «воркер решений → глагол перед возобновлением» СНЯТ — посылка изменилась.** Пункт писался, когда двери в контракте не было и подразумевалось НАКОПЛЕНИЕ: платформа копит решения у себя и скармливает их движку перед `resume`. С дверью канона 0.5.0 накопления не существует — правка ПРИМЕНЯЕТСЯ в момент подачи, и гарантия «до возобновления» у синхронной формы СИЛЬНЕЕ воркерной: применено прежде, чем клиент получил `200`. Проверено исполнением с обеих сторон: движок на стопе ВЫХОДИТ (`cmd/tmctl/main.go:95`=`obs.PanicError, row 176`, код 3), флок не-блокирующий и отпускается ядром на выходе процесса (`store/store.go:187`=`acquireLock takes a non-blocking exclusive flock`), между стопом и возобновлением живого процесса на проекте нет — запинено `pipeline/bankchain_test.go:62-64`=`The door takes the project`; кап 5000 решений выведен ИМЕННО из синхронности («the call stops fitting the caller's timeout»). Остаётся не воркер, а пер-книжная сериализация в обработчике. `Resume` «с решениями как они есть» не тронут. +> ⚠ **Эррата 27.08-з (D39.156, состав пункта 2в): «воркер решений → глагол перед возобновлением» СНЯТ — посылка изменилась.** Пункт писался, когда двери в контракте не было и подразумевалось НАКОПЛЕНИЕ: платформа копит решения у себя и скармливает их движку перед `resume`. С дверью канона 0.5.0 накопления не существует — правка ПРИМЕНЯЕТСЯ в момент подачи, и гарантия «до возобновления» у синхронной формы СИЛЬНЕЕ воркерной: применено прежде, чем клиент получил `200`. Проверено исполнением с обеих сторон: движок на стопе ВЫХОДИТ (`backend/cmd/tmctl/main.go:95`=`obs.PanicError, row 176`, код 3), флок не-блокирующий и отпускается ядром на выходе процесса (`backend/internal/store/store.go:187`=`acquireLock takes a non-blocking exclusive flock`), между стопом и возобновлением живого процесса на проекте нет — запинено `pipeline/bankchain_test.go:62-64`=`The door takes the project`; кап 5000 решений выведен ИМЕННО из синхронности («the call stops fitting the caller's timeout»). Остаётся не воркер, а пер-книжная сериализация в обработчике. `Resume` «с решениями как они есть» не тронут. > ⚠ **Эррата 28.08-и (D39.165 §3, размер мины) — ошибка ОРКЕСТРАТОРА, найденная опровергателем промта P10.** Нота утверждает: «первый же ПРОДОЛЖАЮЩИЙ прогон после первой же правки банка УПАДЁТ». **Переоценено.** Гард снапшота стреляет по СУЩЕСТВУЮЩЕМУ джобу (`backend/internal/pipeline/stagerun.go:48`=`r.Store.EnsureJob` ⚠ (адрес испр. 10.09: строку сдвинул лендинг `3f05fab`) — `EnsureJob` создаёт джоб стадии в момент, когда стадия впервые исполняется), а правка в ГЛАВНОМ окне — стоп подписи `awaiting_bank` — двигает edit-снапшот, когда edit-джобов ЕЩЁ НЕТ: возобновление создаёт их свежими, и гард молчит. Драфт-волна mined-строк не видит вовсе (`backend/internal/pipeline/bankmaterialize.go:321`=`if row.Source == "mined"` (⚠ адрес испр. 06.09; ФОРМУЛИРОВКА испр. по эррате 06.09-ж: переименования НЕ было — `seeding.go` жив, а код ВЫДЕЛЕН в `bankmaterialize.go` (`6ec9f8a` 29.08). Линт не мог угадать адрес по другой и более простой причине: прежний якорь был написан ГОЛЫМ именем, а такое имя отсеивается на `docs/scripts/counts.py:618`=`"~" in rel or "/" not in rel` ДО всякой проверки файла — нашёл `git log -S` по тексту якоря)). **Дефект СТОИТ, но его триггер уже: правка, сделанная ПОСЛЕ появления edit-джобов** — пауза потолком посреди редактуры и ДОЧИТАННАЯ книга. ⚠ Срочность при этом НЕ падает: флагманский случай продукта («поправил имя героя в дочитанной книге») — ровно тот, где edit-джобы существуют, то есть мина бьёт именно по нему. **Цена ошибки была бы прямой:** репро на потоке `awaiting_bank` показало бы ЗЕЛЕНЬ без фикса, и пак мог быть отозван как мнимый. Промт P10 §4.2 исправлен: репро обязано фиксировать состояние «edit-джоб существует ДО правки». > ⚠ **Эррата 28.08-к (D39.165 §3 + решение оркестратора о глава-полосе) — ДВЕ ошибки, обе найдены широким самопроходом платформенной сессии, обе доказаны исполнением.** **(1) Посылка «смета УЖЕ публикуется в `status --json`» верна только ПОСЛЕ свёртки.** `bank-apply` пишет только ФАЙЛЫ решений, а `status` считает ре-билл от СОХРАНЁННОГО глоссария (`backend/internal/pipeline/status.go:1011`=`seed-FILE edit` ⚠ (адрес испр. 06.09 и 10.09 — второй раз строку сдвинул лендинг `3f05fab`: цитата УЕХАЛА, не исчезла; в теле `D39.165` она осталась по прежнему адресу — тело ноты не переписывается, D23.3)``, `projectStoredMemory` — его собственный комментарий: «A seed-FILE edit not yet re-run is NOT reflected here… that drift surfaces on the next translate's re-seed»). Свёртка происходит внутри СЛЕДУЮЩЕГО `translate`, поэтому сразу после правки движок отвечает `units=0`/`drift=false`. Следствие: продажа «затронуто N юнитов» и холд от сметы В ТЕКУЩЕМ ШВЕ НЕДОСТИЖИМЫ — для них нужен движковый глагол «свернуть банк и оценить ВНЕ translate», которого нет. **(2) Решение оркестратора «полоса пере-прохода — в ГЛАВАХ» ОТМЕНЯЕТСЯ: его посылка опровергнута.** Я рассудил, что $0-репин двигает полосу, потому что идёт через тот же `resumeFromChunkStatus`, — и не проверил анонс. Движок анонсирует юнит ОДИН РАЗ на жизнь книги (announce-once, `backend/internal/pipeline/events.go:57`=`announce-once keys`), пере-проход не ре-анонсирует ни репины, ни пере-переводы ⇒ `done` остался бы НУЛЁМ навсегда. Это ровно тот класс, от которого предостерегает памятка «не выводить из соседнего механизма, не проверив свой». ⚠ **Что при этом НЕ отменяется:** запрет класть ЮНИТЫ в поле, объявленное в главах, стоит — но объявленная в каноне «одна единица работы» запретом не является, потому что она НЕ молчаливая. > ⚠ **Эррата 29.08-а (D39.172, две строки, объявленные заведёнными) — ошибка ОРКЕСТРАТОРА №19.** Тело ноты дважды утверждает «Заведено строкой» / «строка заведена» — про `Touch`, выбрасывающий `RowsAffected`, и про пересборку `tmctl` в рецепте стенда. **На момент ратификации ни одной из этих строк не существовало:** последняя строка регистра платформы была `PD-430`, и проверка грепом по `Touch|RowsAffected|пересбор` давала только совпадения слов в чужих строках. Утверждение о будущем записано как о свершившемся — ровно тот класс, который эта же смена ловила у сессий трижды. **СНЯТА 29.08: строки заведены зоной — `PD-431` (`Touch`) и `PD-432` (пересборка `tmctl`), `PD-423` получил вторую точку. Проверено грепом по регистру.** Тело ноты не переписывается (D23.3). ⚠ Сюда же третий пункт того же абзаца: `PD-423` предписано ПЕРЕ-ПРОВЕРИТЬ (у сессии `sqlc` тест зелёный в трёх прогонах), и пометки в строке регистра тоже нет. @@ -435,7 +435,7 @@ Три решения приняты владельцем 25.07 по фактам D39.29. Записаны здесь, потому что это ровно тот класс, который обязан иметь аудит-след: юридическая ось, 18+, принятый риск. 1. **`violence` — лейбл механически НЕ заводится; интерпретация фиксируется письменно (вариант 2 + аудит-след).** Подписанное чтение владельца: **нейтральное художественное изображение насилия в вымысле не является «promoting / inciting / glorifying / facilitating violence»** — то есть под глаголы-пропаганды, которыми оперируют все проверенные AUP, наши тексты не подпадают. Практика: лейбл `violence` в вокабуляре остаётся (механизм его держит), но книгам не назначается и `accepts_labels` им не заполняется — это ровно статус-кво, под которым уже прошли exp10 и rerun2, поэтому нового риска решение не создаёт, а приёмочная 蛊真人 едет как ехала. **Обратимость:** вариант «выдать `violence` вендорам с глаголами-пропагандами» остаётся доступен одной правкой данных в любой момент; `zai` под ним не подпадает в любом случае (плоский запрет), `xai` — тоже (чистое молчание). **Граница честности:** это интерпретация, а не право, выданное текстом; она защищает решение как обдуманное, но не заменяет разъяснения вендора. -2. **Риск Z.AI ПРИНЯТ сознательно, с записью.** Факт: Z.ai Terms of Use (Last Update 2026-04-14) п. f) запрещает «obscene, pornographic, **violent**, murderous, terroristic, or criminal incitement content» — «violent content» плоско, без глагола-пропаганды, то есть в отличие от п.1 здесь интерпретация не спасает. Экспозиция УЖЕ состоялась: glm-арм (`configs/pipeline-arm-glm.yaml`, `role: editor / model: glm-5`) гонялся живьём на 蛊真人 в rerun2 (D39.20). **Решение владельца: риск принять** — прогон исследовательский, на собственной книге, без публикации; glm-5 остаётся резервным армом редактора. **Условия, при которых решение пересматривается (записываю как часть принятия):** переход к публикации/клиентским книгам · использование glm на не-своём контенте · смена политики Z.AI (пере-проверка 2026-10-25). `glm-5.1` в `chains.default` (`configs/pipeline-c1.yaml:109`=`runner.sourceEchoExposure`) остаётся недостижимым по построению (single-hop через `escalate_to`, `budget_usd: 0`), так что дополнительного вектора цепочка не даёт. +2. **Риск Z.AI ПРИНЯТ сознательно, с записью.** Факт: Z.ai Terms of Use (Last Update 2026-04-14) п. f) запрещает «obscene, pornographic, **violent**, murderous, terroristic, or criminal incitement content» — «violent content» плоско, без глагола-пропаганды, то есть в отличие от п.1 здесь интерпретация не спасает. Экспозиция УЖЕ состоялась: glm-арм (`configs/pipeline-arm-glm.yaml`, `role: editor / model: glm-5`) гонялся живьём на 蛊真人 в rerun2 (D39.20). **Решение владельца: риск принять** — прогон исследовательский, на собственной книге, без публикации; glm-5 остаётся резервным армом редактора. **Условия, при которых решение пересматривается (записываю как часть принятия):** переход к публикации/клиентским книгам · использование glm на не-своём контенте · смена политики Z.AI (пере-проверка 2026-10-25). `glm-5.1` в `chains.default` (`backend/configs/pipeline-c1.yaml:111`=`runner.sourceEchoExposure`) остаётся недостижимым по построению (single-hop через `escalate_to`, `budget_usd: 0`), так что дополнительного вектора цепочка не даёт. 3. **Две строки `accepts_labels` ПОДПИСАНЫ и ПРИМЕНЕНЫ мной в `backend/configs/models.yaml`:** `xai: accepts_labels: [sexually-explicit]` (xAI AUP Effective 2026-06-26 + Enterprise ToS Last Updated 2026-05-12) и `mistral: accepts_labels: [sexually-explicit]` (Mistral Usage Policy Effective 2026-06-11, хост `legal.mistral.ai`). Обоснование — в комментариях у строк, цитаты — в `experiments/00-provider-quirks.md`. **Ни одна книга лейблов не несёт, поэтому применение строк НИЧЕГО не запускает и ничего не двигает** (проверено: `go test ./internal/config/` зелёный; строки — данные провайдера, вне хешей и вне снапшотов). Механизм перестал быть пустым и готов к первой explicit-книге; для неё по-прежнему обязательны предусловие D22.7 (L3-скрин) и Q2 (выбор редактора под лейблом). **Остались открытыми (не блокируют, у владельца):** чтение Gemini-оговорки «for example … pornography or sexual gratification» (сужение vs иллюстрация) · связывает ли нас OpenAI Sharing & publication policy 2022 (единственное, что держит обе клетки OpenAI в UNCLEAR) · применимость Ollama ToS §4 к локальному инференсу · различать ли в конфиге причину пустоты (`FORBIDDEN` vs `UNCLEAR`) · дата заведения аккаунта OpenAI (§17 привязывает редакцию политик к дате договора) · ре-чек политик по хешу перед платными прогонами (триггеры: головной Google ToS 30.07.2026, квартал 25.10.2026). **Продуктовое (Ф3, вне движка):** Gemini API Additional ToS запрещает клиентов, «likely to be accessed by individuals under 18» — обязательство на конечный продукт (ридер/публикация). @@ -492,7 +492,7 @@ ## D39.63 — Р2/Р4 ОТВЕЧЕНЫ + ФИГУРА RESNAPSHOT РАСТВОРЕНА ПОСЫЛКОЙ ВЛАДЕЛЬЦА (01.08): **(1) Р2 = ЗНАЧЕНИЕ**: контракт семейства детекторов единиц/шкал (DC1-часы · магнитуды 万/億 · 成-доли · любой пересчёт) — жёсткий флаг ТОЛЬКО за неверное ЗНАЧЕНИЕ; неконвертированная в единицы читателя форма = мягкий счётчик/линт, НЕ дефект (согласуется с precision 1.000 против 0.167 разметки пакета-6); контракт передан фазе-2 промтом; **(2) Р4 — норма подтверждена** («Ладно»): у правила бывает потолок полноты by construction, записывается в контракт правила, «неразрешимая речь/мысль» не дефект и поклассово не переспрашивается ⇒ **строка 1 (Р1–Р4) ЗАКРЫТА ЦЕЛИКОМ** (Р1 расщеплён D39.60, Р3 закрыт D39.44 Q4); **(3) владелец оспорил посылку «один общий resnapshot» — и ПРАВ для текущей фазы**: боевых книг в полёте нет, стендовый корпус ОДНОРАЗОВЫЙ (старые БД остаются читаемым $0-сырьём, перекупать их не для чего), каждый следующий замер — СВЕЖИЙ мини-прогон на новом стеке ⇒ фигура D39.60 п.(2) вырождается в дисциплину секвенирования: платных замеров не покупать, пока фаза-2 не залендена (иначе меряем вчерашний стек); механика `--resnapshot`/условных фолдов/П0-хеширования остаётся и строится — она про эру боевых книг после МАСШТАБА; побочное упрощение: данные-правки (шестёрка · #8 两 · класс speech-cue) на этой фазе перестают быть «дорогими»; **(4) развилка 74 — оперативное состояние «(в) ждать» по умолчанию**: платных прогонов до конца фазы-2 нет; перед следующим платным прогоном — ре-проба flash за копейки, довесок того же прогона — итерация №2 редакторов (D39.22); **(5) само-ревью выданных промтов по вопросу владельца — три дыры найдены и закрыты правками**: контракт Р2 вписан бэкенду · заметка о параллельной сессии и заморозке бинаря — обоим · карта чтения — полигону; параллельный запуск двух сессий подтверждён безопасным (зоны и артефакты не пересекаются) (01.08, оркестратор №9). ✅ -## D39.64 — ОБЩНОСТЬ ФАЗА 2 ПРИНЯТА И ЗАЛЕНДЕНА ($0 — ноль платных вызовов, `--resnapshot` НЕ запускался; приёмка исполнением + адверсариальное 6-агентное ревью оркестратора: ни одно несущее утверждение отчёта не опровергнуто): построено **П0** — `lang.EmbeddedVersion()` (sha256 эмбед-данных, framing как у `Load`) БЕЗУСЛОВНЫМ фолдом в снапшот, дыра эмбед-плоскости ЗАКРЫТА (строка 76; мутационный тест: байт `target-ru.txt`/`injection.txt` = громкий resnapshot); **П1 цель-шов слоя 7 по данным** — `isRuTarget`×6 УДАЛЁН → `TargetActive()`/`TargetScriptNonLatin()`, токенизатор цели `TokenizeScript` с алфавитом из `word_script` данных + Mn-фолд U+0301 (#11 закрыт) = ЕДИНЫЙ шов линт↔репэйр (долг `repair.go` РЕПЭЙНУТ), `ExportNormalize`-гейт (7 сайтов), `ruSanitizer`→per-run поля `Checkers`, реестр целей из эмбед-файлов; книга `target_lang: en` инертна ПО ОТСУТСТВИЮ данных (мут.тест) — строка 32 ЗАКРЫТА; **П2 скрипт-шов источника** — `cjkShare`→`sourceScriptShare` по ОБЪЯВЛЕННОМУ письму (новый `lang-script.txt` + единый реестр `scriptRanges`), Hangul в CJK-leak: живой баг ko ЗАКРЫТ (строка 75), en/ko-эхо больше не слепые (вердикт-вокабуляр `cjk_artifact` сохранён); **П3** — 話-глава данными · sourceAbbrevs по языку книги · generic-детект глав без units («Chapter 12») · sizing-таксономия в ОДНОМ доме (`text.DenseScript`); **П4** — табличные опц-файлы + манифест-по-каналам: источник без пиньинь-морфологии грузится без Palladius-файлов, манифест-less пак БАЙТ-ИДЕНТИЧЕН (`langpack-v2-a28ed743c99c` — независимая проба оркестратора HEAD-vs-дерево), `packAlgoVersion` НЕ бампался — самый жёсткий блокер слоя данных СНЯТ; **шестёрка 2/6** — #11 + `translitInterjections`→данные (строка 26 закрыта); **#77** — ручка `RegenerateEchoBeforeEscalate` (дефолт 0 = байт-в-байт текущее поведение; гейт D19.2 не тронут; включение — решением при ре-пробе 74; при включении помнить: общий счётчик attempt с length-ре-геном + рост `maxTokensForAttempt` на каждом ре-гене). Верификация оркестратора: `-race` 14/14 · **Ш-1 НЕЗАВИСИМОЙ классификацией диффа голдена: 172 строки = ровно 5 осей** (`embedded_version` НОВАЯ · cheapgate-v6 · sanitizer-v7-hangul-leak · classify-v2 · chunker-v6; content_hash/disp/wire-тела/stage_text — 0) · майнер-парити EXACT (`n=13618`, катастрофы точны, recall 0.9655) · перекупок НЕТ (D39.63). Приёмочный критерий «пара, которой нет в репо, проходит слой без правки Go» ДЕРЖИТСЯ для П0/П1/П2/П4 + generic-П3 (свип: новых языковых ветвлений диф не внёс; остатки = документированные ru-дефолт-обёртки + флаги). **9 флагов §5 (не «10» — off-by-one) — очередь владельца (строка 14):** ё-фолд→данные (вердикт-несущий банк, сдвиг `memory_version`) · segmentation-фолбэк громким (ломает контракт corridor-фолбэка — `pipeline.go:839-848` + голден-фикстура на нём) · Fertility-map (калибровка ждёт боевого токенизатора) · encoding-реестр · 4 дефекта пака-21 → пакет-чекеров при свежем мини-прогоне (корпус `labels/` на стенде ЕСТЬ — барьер = утраченный в scratch харнесс) · #78 money-путь (дизайн §5.6 готов, не $0-хастл — строка 78 остаётся). Новая строка 79: остаточные Cyrillic-хардкоды пар-гейтед DC-чекеров (`checks/repair.go:131`=`declared word script, not a hardcoded Cyrillic predicate` · `checkers.go:457,474`) — инертны без dc-данных пары, кандидат на `c.wordScript`. Строки 72 · 75 · 76 · 77 · 26 · 32 ЗАКРЫТЫ (01.08, оркестратор №9). ✅ +## D39.64 — ОБЩНОСТЬ ФАЗА 2 ПРИНЯТА И ЗАЛЕНДЕНА ($0 — ноль платных вызовов, `--resnapshot` НЕ запускался; приёмка исполнением + адверсариальное 6-агентное ревью оркестратора: ни одно несущее утверждение отчёта не опровергнуто): построено **П0** — `lang.EmbeddedVersion()` (sha256 эмбед-данных, framing как у `Load`) БЕЗУСЛОВНЫМ фолдом в снапшот, дыра эмбед-плоскости ЗАКРЫТА (строка 76; мутационный тест: байт `target-ru.txt`/`injection.txt` = громкий resnapshot); **П1 цель-шов слоя 7 по данным** — `isRuTarget`×6 УДАЛЁН → `TargetActive()`/`TargetScriptNonLatin()`, токенизатор цели `TokenizeScript` с алфавитом из `word_script` данных + Mn-фолд U+0301 (#11 закрыт) = ЕДИНЫЙ шов линт↔репэйр (долг `repair.go` РЕПЭЙНУТ), `ExportNormalize`-гейт (7 сайтов), `ruSanitizer`→per-run поля `Checkers`, реестр целей из эмбед-файлов; книга `target_lang: en` инертна ПО ОТСУТСТВИЮ данных (мут.тест) — строка 32 ЗАКРЫТА; **П2 скрипт-шов источника** — `cjkShare`→`sourceScriptShare` по ОБЪЯВЛЕННОМУ письму (новый `lang-script.txt` + единый реестр `scriptRanges`), Hangul в CJK-leak: живой баг ko ЗАКРЫТ (строка 75), en/ko-эхо больше не слепые (вердикт-вокабуляр `cjk_artifact` сохранён); **П3** — 話-глава данными · sourceAbbrevs по языку книги · generic-детект глав без units («Chapter 12») · sizing-таксономия в ОДНОМ доме (`text.DenseScript`); **П4** — табличные опц-файлы + манифест-по-каналам: источник без пиньинь-морфологии грузится без Palladius-файлов, манифест-less пак БАЙТ-ИДЕНТИЧЕН (`langpack-v2-a28ed743c99c` — независимая проба оркестратора HEAD-vs-дерево), `packAlgoVersion` НЕ бампался — самый жёсткий блокер слоя данных СНЯТ; **шестёрка 2/6** — #11 + `translitInterjections`→данные (строка 26 закрыта); **#77** — ручка `RegenerateEchoBeforeEscalate` (дефолт 0 = байт-в-байт текущее поведение; гейт D19.2 не тронут; включение — решением при ре-пробе 74; при включении помнить: общий счётчик attempt с length-ре-геном + рост `maxTokensForAttempt` на каждом ре-гене). Верификация оркестратора: `-race` 14/14 · **Ш-1 НЕЗАВИСИМОЙ классификацией диффа голдена: 172 строки = ровно 5 осей** (`embedded_version` НОВАЯ · cheapgate-v6 · sanitizer-v7-hangul-leak · classify-v2 · chunker-v6; content_hash/disp/wire-тела/stage_text — 0) · майнер-парити EXACT (`n=13618`, катастрофы точны, recall 0.9655) · перекупок НЕТ (D39.63). Приёмочный критерий «пара, которой нет в репо, проходит слой без правки Go» ДЕРЖИТСЯ для П0/П1/П2/П4 + generic-П3 (свип: новых языковых ветвлений диф не внёс; остатки = документированные ru-дефолт-обёртки + флаги). **9 флагов §5 (не «10» — off-by-one) — очередь владельца (строка 14):** ё-фолд→данные (вердикт-несущий банк, сдвиг `memory_version`) · segmentation-фолбэк громким (ломает контракт corridor-фолбэка — `pipeline.go:839-848` + голден-фикстура на нём) · Fertility-map (калибровка ждёт боевого токенизатора) · encoding-реестр · 4 дефекта пака-21 → пакет-чекеров при свежем мини-прогоне (корпус `labels/` на стенде ЕСТЬ — барьер = утраченный в scratch харнесс) · #78 money-путь (дизайн §5.6 готов, не $0-хастл — строка 78 остаётся). Новая строка 79: остаточные Cyrillic-хардкоды пар-гейтед DC-чекеров (`backend/internal/checks/repair.go:131`=`declared word script, not a hardcoded Cyrillic predicate` · `checkers.go:457,474`) — инертны без dc-данных пары, кандидат на `c.wordScript`. Строки 72 · 75 · 76 · 77 · 26 · 32 ЗАКРЫТЫ (01.08, оркестратор №9). ✅ ## D39.69 — КАЧЕСТВО БАНКА: ОБА ЭТАПА ПРИНЯТЫ И ЗАЛЕНДЕНЫ (этап 1 дизайн ратифицирован ВЛАДЕЛЬЦЕМ напрямую; этап 2 стройка той же сессией, $0, чекер-пак ещё не стартовал — коллизий нет; приёмка оркестратора: тесты/парити/голден исполнением + независимое воспроизведение флагманских чисел + 4-агентное адверсариальное ревью): **ПОСТРОЕНО ТРИ ПРИМИТИВА** — **§1 серия-батчинг (36в ЗАКРЫТА)**: `DetectSeries` HEAD-AWARE (равная длина · общая голова · различие только в модификаторе · L=1 вне · без транзитивного замыкания) + серия ЦЕЛИКОМ в батч + value-порядок отреза бюджета (частота-desc — **feed_cap ЗАКРЫТ этим**, из строки 86 изъят); канал по классу письма из данных (`lang-script.txt`), алфавитный источник инертен; «ровно 4 серии на живом BANK-FULL, ноль блоба, 方源/元石/元海 вне» — воспроизведено оркестратором НЕЗАВИСИМО; **§2 тип-классификатор ПЕРВИЧНЫМ (36а ЗАКРЫТА)**: отдельная фокус-фаза ДО RenderBatch (единственная форма с живой пробой 6/6), корректный тип роутит conform + праймит рендер + банкуется `attachClassifiedType` БЕЗ смены эмиссии (D39.50 не реоткрыт); своя роль/бюджет/промт `classifier.md`, request-hash-ось, fail-loud пары без промпта; честный $0-экран (тест ПИНИТ, что он пропускает юаньши/Юаньхай — флаг, не гейт); денежный цикл терминолога зарефакторен в общий `runBankRoleBatches` (resume $0 запинен тестом); **§3 Decl-шов (строки 27/84 ЗАКРЫТЫ)**: `lang.TargetStemmer` из ru-ДАННЫХ `decl_suffix` (пара без данных инертна) → `dstFormPresent` принимает косвенные падежи; короткая форма 27 — уже работала через `decl.forms[]` (пин пре-существующим тестом); neuter end-to-end (enum · `gender_neuter` в injection-данных · SeedLint громко отбраковывает неизвестный род); ось = **scoped `neuter-directive-v1`-фолд в `memory_version`** (отступление от дизайна ПРИНЯТО как улучшение — точнее правила условного фолда §6.2, книга без neuter байт-идентична, голден доказал). **ЗАКРЫТО ПО НУЖНОСТИ дизайном (ратификация закрытий):** 36б второе мнение — бэкенд-стройки НЕТ, маршрут = полигон-замер (Q2, строка 5 перевязана) · резюме-слой (строка 80) — проза-суммарайзер закрыт, строка = ГЕЙТ ПИЛОТА Ф2.5 («допускает ли нарратив-строка детерминированный верификатор — или это D1 со схемой») · эмиссия головы 蛊 — сид-половина (чек-лист) + измер-гейт Q7 ПОСЛЕ #10 (строка 18 перевязана) · эмбеддинг A7/D2 — закрыт по нужности, реопен = измеренный recall-разрыв на МАСШТАБЕ, только batch-time лейн · STITCH — закрыт до давления МАСШТАБА (реопен = бюджет ИЛИ измеренный эффект размера инъекции) · ranked-set — качество закрыто §1, hard-режим = Q4. **First-occurrence-тест ($0, исполнен): гипотеза первенства ОПРОВЕРГНУТА** — роль не первовхожденческий и не частотный выбиратель, ре-решает контекстом (позитивное подтверждение D39.65). **Голден: 172/172 hex-only** (сдвиг = `embedded_version` от данных injection/target-ru), вердикты байт-идентичны. **Фикс-лист → строка 87** (несущее: «ь» в `decl_suffix` — приёмочный кейс «Фан Юаню» сейчас ПРОВАЛИВАЕТСЯ; неверный комментарий Batch про независимость request-hash; оверсайз-серия одним батчом — помнить cap-8000; classify-валидация/тесты; мутационный тест neuter; voice-stemmer вопрос). **⚠ Вопрос владельцу Q8: `classifier.md` несёт книжные каноны (方源 и др.) в общий пар-слой** — санкция или жанрово-генерические примеры. Вопросы §9 Q1–Q7 + Q8 — строка 88. Платный порог «6/6 harm» — добрать при ре-пробе 74 (02.08, оркестратор №9). ✅ @@ -504,11 +504,11 @@ ## D39.81 — Фронт открыт: SaaS ратифицирован, процессная модель движка, инвариант непротекания конвейера, бэкенд-работы Ф3 получили строки (02.08) -По релею записки фронт-направления; все несущие техутверждения сверены кодом до записи (HTTP-слоя в backend нет — 0 вхождений ListenAndServe; рамка research/16:13 «выхлоп = экспорт-артефакты, НЕ веб-сервер; API/SSE — Ф3» дословна; `pipeline/ratelimit.go:11`=`N-CONCURRENCY against a rate-limited model` — гарды per-процесс, mistral ~48% отказов под параллелизмом; `store.go:43` EXCLUSIVE flock + `OpenReadOnly`-пути без flock; банк-пауза `--verify-bank` построена). Ратифицировано: **(1) Продукт = SaaS**, не локальное приложение (решение владельца 02.08); зоны `frontend/` (фронт-сессия на моках, промт `frontend/docs/FRONTEND_SESSION_PROMPT.md`) и `platform/` (control plane) — живые, роль «Платформа» в CLAUDE.md; натив-прицел V0-п.26 снят этим решением (реестр ПТ-23). **(2) Инвариант непротекания конвейера:** интерфейс не раскрывает модели/стадии/внутреннюю терминологию — пользователь видит «загрузка → разбор → перевод → подпись банка → финал → готово»; API отдаёт продуктовые понятия, слой перевода внутренних вердиктов обязателен (сегодняшний read-model с flag_reason/стадиями наружу не выдаётся); ревью-вопрос — зеркало общности: «сменится стадия конвейера — придётся ли править фронт?» (реестр ПТ-33). **(3) Процессная модель:** движок = процесс-на-прогон (EXCLUSIVE flock — инвариант, не ограничение); СЕРВЕР В backend НЕ ПИШЕТСЯ — HTTP/SSE и пользователи/квоты/очередь живут в `platform/`; read-API строится поверх готовых `OpenReadOnly`-путей. **(4) Строки:** НОВЫЕ 95 «контракт API v0 + продуктовый словарь статусов» ($0; ЕДИНСТВЕННАЯ ранняя вставка — фронт на моках, без пришпиленного контракта моки и API разойдутся классом «док↔код»; двухфазный поток вывести из готового `--verify-bank`, не проектировать) · 96 «HTTP/SSE + сервисная обвязка в platform» (Ф3, после 95) · 97 «глобальный брокер рейт-лимитов» (гейт «до второго параллельного пользователя»); ПЕРЕВЕСЫ: 49 annot-половина D15.2 → «скоро» (annot-v1 = источник замечаний фронта, критический путь подключения) · 94 → «к подключению фронта». **(5) Курс НЕ пере-упорядочен:** движковая очередь (смолпак → ре-проба 74 → добор идеала → ja→ru → МАСШТАБ) стоит — фронт бэкенда не ждёт. Поправки записке при приёмке: реестр требований, который она предлагает завести, УЖЕ построен (D39.80, `product-requirements.md`); H7/H8/H10 уже несла строка 94; ETA — строка 54; H-требования сверены — статусы записки совпали с реестром (02.08.2026, оркестратор №9, по релею владельца «надо записать в планы»). ✅ +По релею записки фронт-направления; все несущие техутверждения сверены кодом до записи (HTTP-слоя в backend нет — 0 вхождений ListenAndServe; рамка research/16:13 «выхлоп = экспорт-артефакты, НЕ веб-сервер; API/SSE — Ф3» дословна; `backend/internal/pipeline/ratelimit.go:11`=`N-CONCURRENCY against a rate-limited model` — гарды per-процесс, mistral ~48% отказов под параллелизмом; `store.go:43` EXCLUSIVE flock + `OpenReadOnly`-пути без flock; банк-пауза `--verify-bank` построена). Ратифицировано: **(1) Продукт = SaaS**, не локальное приложение (решение владельца 02.08); зоны `frontend/` (фронт-сессия на моках, промт `frontend/docs/FRONTEND_SESSION_PROMPT.md`) и `platform/` (control plane) — живые, роль «Платформа» в CLAUDE.md; натив-прицел V0-п.26 снят этим решением (реестр ПТ-23). **(2) Инвариант непротекания конвейера:** интерфейс не раскрывает модели/стадии/внутреннюю терминологию — пользователь видит «загрузка → разбор → перевод → подпись банка → финал → готово»; API отдаёт продуктовые понятия, слой перевода внутренних вердиктов обязателен (сегодняшний read-model с flag_reason/стадиями наружу не выдаётся); ревью-вопрос — зеркало общности: «сменится стадия конвейера — придётся ли править фронт?» (реестр ПТ-33). **(3) Процессная модель:** движок = процесс-на-прогон (EXCLUSIVE flock — инвариант, не ограничение); СЕРВЕР В backend НЕ ПИШЕТСЯ — HTTP/SSE и пользователи/квоты/очередь живут в `platform/`; read-API строится поверх готовых `OpenReadOnly`-путей. **(4) Строки:** НОВЫЕ 95 «контракт API v0 + продуктовый словарь статусов» ($0; ЕДИНСТВЕННАЯ ранняя вставка — фронт на моках, без пришпиленного контракта моки и API разойдутся классом «док↔код»; двухфазный поток вывести из готового `--verify-bank`, не проектировать) · 96 «HTTP/SSE + сервисная обвязка в platform» (Ф3, после 95) · 97 «глобальный брокер рейт-лимитов» (гейт «до второго параллельного пользователя»); ПЕРЕВЕСЫ: 49 annot-половина D15.2 → «скоро» (annot-v1 = источник замечаний фронта, критический путь подключения) · 94 → «к подключению фронта». **(5) Курс НЕ пере-упорядочен:** движковая очередь (смолпак → ре-проба 74 → добор идеала → ja→ru → МАСШТАБ) стоит — фронт бэкенда не ждёт. Поправки записке при приёмке: реестр требований, который она предлагает завести, УЖЕ построен (D39.80, `product-requirements.md`); H7/H8/H10 уже несла строка 94; ETA — строка 54; H-требования сверены — статусы записки совпали с реестром (02.08.2026, оркестратор №9, по релею владельца «надо записать в планы»). ✅ ## D39.84 — Стек фронта/платформы запинен, восемь решений владельца ратифицированы, работы движка под фронт получили строки, перевод не индексируется (02.08) -По релею отчёта фронт-сессии (исследование стека закрыто: 15 агентов — 7 направлений × независимые скептики-опровергатели + синтез, версии сверены с вебом 02.08, blocker/major-поправки скептиков записаны исправленными вариантами; артефакты `frontend/docs/STACK_DECISIONS.md` и переписанный `frontend/docs/FRONTEND_SESSION_PROMPT.md` — фронт режется на этапы S0–S7, первая кодовая сессия кончается витриной токенов). Приёмка оркестратора: 10-агентный refute-воркфлоу — ВСЕ несущие бэкенд-утверждения записки CONFIRMED по коду, 8/8 веб-пинов подтверждены первоисточниками (TS7 GA 08.07.2026 БЕЗ программного API до 7.1 → TS 6.0.3 · Vite 8 = Rolldown · Fleet закрыт 22.12.2025 · react-resizable-panels v4 Group/Separator · react-router 8.3 Node≥22.22 — стенд 22.22.3 проходит). **(1) Восемь решений владельца:** рынок глобальный, SEO только Google (Яндекс снят) · выравнивание колонок грубое по единицам экспорта — механизм ГОТОВ (`tmctl export --pairs`, побайтное выравнивание по edit-unit, `internal/pipeline/export.go:89-93`=`PendingUnits int`; уточнение приёмки: draft-only-пайплайн шипит по чанкам, для штатного edit-пайплайна утверждение точно) · подсветка сомнительных мест только блок/глава, внутритекстовые спаны НЕ строятся (у $0-гейтов нет байтовых смещений) · остановка на подписи банка = параметр запуска per-run — ГОТОВО (`--verify-bank`, exit 3, `invocation.go:108`/`main.go:39-46`; галочка формы = передача флага, движок не трогается; в draft-only не останавливает — `mining.go:193-197`) · оплат в MVP нет, денежных полей в UI нет вовсе (расход остаётся телеметрией владельца; потолки/rebill-согласие движка канон §5 не трогает) · десктоп = устанавливаемое PWA первым шагом, Tauri по явным триггерам · макет-инструменты не используются, источник вида = пиксель-замеры референса (Fleet невоспроизводим — растровое совпадение не критерий готовности) · аутентификация: ОДНА серверная сессия, предъявление кукой (браузер) или Bearer (десктоп/CLI), principal только в middleware — вход дизайна П-1 платформенного бэклога. **(2) ПТ-34, продуктовый запрет:** ни один символ пользовательского перевода никогда не попадает на публично индексируемый URL — ни витрин, ни «поделиться», ни публичных ссылок чтения (авторское право + политика Google по масштабируемому машин-контенту бьют по всему домену); носитель — двухконтурный деплой (SPA `app.<домен>` целиком под noindex + статический публичный контур, STACK_DECISIONS §4). **(3) ПТ-21 переформулировано:** якорь чтения = edit-unit экспорта, НЕ «чанк пайплайна» — финальный текст существует только на уровне юнита (~1.9 юнита/главу по замеру фронта; «4276 юнитов» из артефактов репо не выводится — полнокнижной БД не существует, что само подтверждает тезис о ре-ингесте; принято как замер сессии, порядок величин сходится с coldrun-a); читалка обязана жить с «глава = один блок». **(4) Работы движка → строки 99–102** (каждая проверена кодом): 99 пофазный прогресс draft N/M ∥ edit N/M (done = все draft-строки членов + edit-строка, `status.go:328-331/365` — индикатор 0% ВСЮ черновую волну; `chunk_status` уже несёт гранулярность — выводимо без миграции схемы) · 100 персист манифеста глав/чанков + хеш источника (каждый read-вызов заново ингестит и режет исходник — `status.go:177-195`, redrive дважды за вызов; замер фронта 1.42–1.51 с CPU/23 МБ; `chunker_version` уже в снапшоте — `pipeline/render.go:53`=`reclassifies a rune would silently re-chunk the book`) · 101 машиночитаемая таблица подписи банка (кап 20 = только stdout `render.go:98`; полная таблица — текстовый сайдкар `.bank-stop.txt`; JSON нет нигде) · 102 внешний trace-контекст в tmctl (TraceID минтится заново каждым вызовом — `main.go:67-70`; внутри вызова трасса цельная, `request_log.trace_id` персистится). **(5) Противоречие разрешено ВЕРНО:** рекомендация интеграционного агента «долгоживущий демон в backend» отвергнута самой сессией по D39.81 — ратификация удержана, HTTP/SSE/очередь в `platform/`. **(6) Две ловушки эксплуатации подтверждены и заведены входами дизайна (строка 95 · П-1):** подпись термина ≠ UPDATE строки — банк пересобирается каждым прогоном (seedGlossary REPLACES + ReplaceBank DELETE/re-INSERT, `seeding.go:18/110`, `glossary.go:158-162`; контракт подписи пишет в файлы-источники: mined-delta/сид; след затирания — только журнальная строка glossary_revisions, без предупреждения) · порядок деплоя платформы: read-путь схему НЕ мигрирует никогда (`store.go:135-143`, «schema vN … expects vM» в обе стороны; чинит write-команда, годится и `redrive --dry-run`; `tmctl backup` НЕ мигрирует). **(7) Норма зонных бэклогов (решение владельца при лендинге):** фронт и платформа держат СВОИ бэклоги в своих зонах — `frontend/docs/BACKLOG.md` (Ф-1..Ф-6) · `platform/BACKLOG.md` (П-1..П-4); засеяны оркестратором при лендинге переносом уже записанных отложенных решений, дальше ведут зоны; ЕДИНЫЙ бэклог PROGRESS фронт/платформа-строк НЕ принимает — остаётся трекером движка/полигона/доков; движковые стыки фронта (зона «бэкенд») живут в едином (строки 99–102); строки 96/97 переехали в платформенный (П-1/П-2) с ID-надгробиями-указателями (ID стабильны навсегда — внешние ссылки не рвутся). **(8) Лендинг зон** `frontend/` + `platform/` + `.gitignore` (`frontend/references/` — скриншоты вне git, пины замеров сохранены в доках). (02.08.2026, оркестратор №9). ✅ +По релею отчёта фронт-сессии (исследование стека закрыто: 15 агентов — 7 направлений × независимые скептики-опровергатели + синтез, версии сверены с вебом 02.08, blocker/major-поправки скептиков записаны исправленными вариантами; артефакты `frontend/docs/STACK_DECISIONS.md` и переписанный `frontend/docs/FRONTEND_SESSION_PROMPT.md` — фронт режется на этапы S0–S7, первая кодовая сессия кончается витриной токенов). Приёмка оркестратора: 10-агентный refute-воркфлоу — ВСЕ несущие бэкенд-утверждения записки CONFIRMED по коду, 8/8 веб-пинов подтверждены первоисточниками (TS7 GA 08.07.2026 БЕЗ программного API до 7.1 → TS 6.0.3 · Vite 8 = Rolldown · Fleet закрыт 22.12.2025 · react-resizable-panels v4 Group/Separator · react-router 8.3 Node≥22.22 — стенд 22.22.3 проходит). **(1) Восемь решений владельца:** рынок глобальный, SEO только Google (Яндекс снят) · выравнивание колонок грубое по единицам экспорта — механизм ГОТОВ (`tmctl export --pairs`, побайтное выравнивание по edit-unit, `internal/pipeline/export.go:89-93`=`PendingUnits int`; уточнение приёмки: draft-only-пайплайн шипит по чанкам, для штатного edit-пайплайна утверждение точно) · подсветка сомнительных мест только блок/глава, внутритекстовые спаны НЕ строятся (у $0-гейтов нет байтовых смещений) · остановка на подписи банка = параметр запуска per-run — ГОТОВО (`--verify-bank`, exit 3, `invocation.go:108`/`main.go:39-46`; галочка формы = передача флага, движок не трогается; в draft-only не останавливает — `mining.go:193-197`) · оплат в MVP нет, денежных полей в UI нет вовсе (расход остаётся телеметрией владельца; потолки/rebill-согласие движка канон §5 не трогает) · десктоп = устанавливаемое PWA первым шагом, Tauri по явным триггерам · макет-инструменты не используются, источник вида = пиксель-замеры референса (Fleet невоспроизводим — растровое совпадение не критерий готовности) · аутентификация: ОДНА серверная сессия, предъявление кукой (браузер) или Bearer (десктоп/CLI), principal только в middleware — вход дизайна П-1 платформенного бэклога. **(2) ПТ-34, продуктовый запрет:** ни один символ пользовательского перевода никогда не попадает на публично индексируемый URL — ни витрин, ни «поделиться», ни публичных ссылок чтения (авторское право + политика Google по масштабируемому машин-контенту бьют по всему домену); носитель — двухконтурный деплой (SPA `app.<домен>` целиком под noindex + статический публичный контур, STACK_DECISIONS §4). **(3) ПТ-21 переформулировано:** якорь чтения = edit-unit экспорта, НЕ «чанк пайплайна» — финальный текст существует только на уровне юнита (~1.9 юнита/главу по замеру фронта; «4276 юнитов» из артефактов репо не выводится — полнокнижной БД не существует, что само подтверждает тезис о ре-ингесте; принято как замер сессии, порядок величин сходится с coldrun-a); читалка обязана жить с «глава = один блок». **(4) Работы движка → строки 99–102** (каждая проверена кодом): 99 пофазный прогресс draft N/M ∥ edit N/M (done = все draft-строки членов + edit-строка, `status.go:328-331/365` — индикатор 0% ВСЮ черновую волну; `chunk_status` уже несёт гранулярность — выводимо без миграции схемы) · 100 персист манифеста глав/чанков + хеш источника (каждый read-вызов заново ингестит и режет исходник — `status.go:177-195`, redrive дважды за вызов; замер фронта 1.42–1.51 с CPU/23 МБ; `chunker_version` уже в снапшоте — `backend/internal/pipeline/render.go:53`=`reclassifies a rune would silently re-chunk the book`) · 101 машиночитаемая таблица подписи банка (кап 20 = только stdout `render.go:98`; полная таблица — текстовый сайдкар `.bank-stop.txt`; JSON нет нигде) · 102 внешний trace-контекст в tmctl (TraceID минтится заново каждым вызовом — `main.go:67-70`; внутри вызова трасса цельная, `request_log.trace_id` персистится). **(5) Противоречие разрешено ВЕРНО:** рекомендация интеграционного агента «долгоживущий демон в backend» отвергнута самой сессией по D39.81 — ратификация удержана, HTTP/SSE/очередь в `platform/`. **(6) Две ловушки эксплуатации подтверждены и заведены входами дизайна (строка 95 · П-1):** подпись термина ≠ UPDATE строки — банк пересобирается каждым прогоном (seedGlossary REPLACES + ReplaceBank DELETE/re-INSERT, `seeding.go:18/110`, `glossary.go:158-162`; контракт подписи пишет в файлы-источники: mined-delta/сид; след затирания — только журнальная строка glossary_revisions, без предупреждения) · порядок деплоя платформы: read-путь схему НЕ мигрирует никогда (`store.go:135-143`, «schema vN … expects vM» в обе стороны; чинит write-команда, годится и `redrive --dry-run`; `tmctl backup` НЕ мигрирует). **(7) Норма зонных бэклогов (решение владельца при лендинге):** фронт и платформа держат СВОИ бэклоги в своих зонах — `frontend/docs/BACKLOG.md` (Ф-1..Ф-6) · `platform/BACKLOG.md` (П-1..П-4); засеяны оркестратором при лендинге переносом уже записанных отложенных решений, дальше ведут зоны; ЕДИНЫЙ бэклог PROGRESS фронт/платформа-строк НЕ принимает — остаётся трекером движка/полигона/доков; движковые стыки фронта (зона «бэкенд») живут в едином (строки 99–102); строки 96/97 переехали в платформенный (П-1/П-2) с ID-надгробиями-указателями (ID стабильны навсегда — внешние ссылки не рвутся). **(8) Лендинг зон** `frontend/` + `platform/` + `.gitignore` (`frontend/references/` — скриншоты вне git, пины замеров сохранены в доках). (02.08.2026, оркестратор №9). ✅ ## D39.85 — Шов движок↔платформа: индустриальный стандарт ратифицирован — событийный поток, материализация, артефакты; ресёрч записан (02.08) @@ -2944,7 +2944,7 @@ $2.00» не мерил никто), **а утверждение о ПРОШЛО **3. ⭐⭐ ГЛАВНОЕ ЗА СМЕНУ: ПИН БЫЛ, ЗЕЛЁНЫЙ И НАСТОЯЩИЙ, А УТВЕРЖДЕНИЕ ВСЁ РАВНО УЕХАЛО.** Первая редакция правки цитировала `httpapi.TestABooksCutProvenanceIsTheEnginesOwnWordOrAnExplicitNull` и иллюстрировала `null` книгой в статусе `not_started` — «fully uploaded, no manifest». Но `BookStatus` В ТОМ ЖЕ ДОКУМЕНТЕ говорит «`not_started` **cut**, never run». Пин при этом верен: он доказывает, что пустая колонка едет на провод как явный `null`. ⇒ **доказано ОТОБРАЖЕНИЕ, а сказано про ЖИЗНЬ; фикстура прочитана как продуктовое состояние.** ⚠ **Класс ловится НЕ тем вопросом, что предыдущие:** «чем это подпёрто?» здесь даёт честный ответ «пином», и проверяющий проходит мимо. **Цитируя пин в утверждении о ЗНАЧЕНИИ, спрашивать надо не «зелен ли он», а «ТО ЛИ ОН МЕРИТ».** Формулировка зоны, ратифицирую. -**4. Ответ пином, и ложной оказалась ИЛЛЮСТРАЦИЯ, а не словарь.** `FinishParse` переводит книгу `parsing → not_started` **и в той же транзакции взводит долг на дерево** (`platform/internal/pgstore/books.go:349`=`FinishParse records a parsed book`): провенанс приходит ПОЗЖЕ, когда материализатор долг оплатит, и окно «разрезана, провенанса нет» — устройство, а не гонка. Пин уровня ХРАНИЛИЩА заведён под этот вопрос: `pgstore.TestAParsedBookIsNotStartedBeforeItHasAnyProvenance` — прогоняет интейк и получает пару «`not_started` + пустой `structure`» от самой базы. ⇒ `not_started` говорит, что разрезан ИСХОДНИК, а не что прочитан манифест; обе строки канона верны. ⚠ К `null` ведут ещё две дороги, ни одна не про книгу в полёте: манифест СТАРШЕ поля и книга, заведённая из файла, уже лежащего на диске (`books.go:88`=`AddBook registers a book`). Канон держит два предмета раздельно: пин хранилища — про жизнь, пин провода — про отображение. +**4. Ответ пином, и ложной оказалась ИЛЛЮСТРАЦИЯ, а не словарь.** `FinishParse` переводит книгу `parsing → not_started` **и в той же транзакции взводит долг на дерево** (`platform/internal/pgstore/books.go:349`=`FinishParse records a parsed book`): провенанс приходит ПОЗЖЕ, когда материализатор долг оплатит, и окно «разрезана, провенанса нет» — устройство, а не гонка. Пин уровня ХРАНИЛИЩА заведён под этот вопрос: `pgstore.TestAParsedBookIsNotStartedBeforeItHasAnyProvenance` — прогоняет интейк и получает пару «`not_started` + пустой `structure`» от самой базы. ⇒ `not_started` говорит, что разрезан ИСХОДНИК, а не что прочитан манифест; обе строки канона верны. ⚠ К `null` ведут ещё две дороги, ни одна не про книгу в полёте: манифест СТАРШЕ поля и книга, заведённая из файла, уже лежащего на диске (`platform/internal/pgstore/books.go:88`=`AddBook registers a book`). Канон держит два предмета раздельно: пин хранилища — про жизнь, пин провода — про отображение. **5. Базовая линия гейта алармов поднята 12 → 14, и это ЗАКОННО — проверено устройством, а не словом.** База есть ДЛИНА объявленного списка: гейт краснеет и на необъявленный новый ряд («add its id here in the same change and say why»), и на объявление, пережившее свою причину. ⇒ поднять её молча нельзя; зона назвала оба ряда с доводом там, где гейт этого требует. **Это исполнение инструкции гейта, а не его обезвреживание** — различение, без которого `D39.121` читается как запрет любой правки базовой линии. @@ -3177,7 +3177,7 @@ mined-посадки (её поверхность есть подстрока у - **Подавлять повторный репорт пары на ре-сиде — НЕТ.** Это разные СОСТОЯНИЯ одного термина: «роль расходится с банком» до посадки строки и «банк держит обе» после; две строки на проводе означает только второе. Резать надо было бы слияние, а не схлопывание. Названо в доке зоны, носитель не нужен. -- **`bookfile/model.go:59`=`before the reader learned to fold an uncovered leading doc` разросся до 183 строк — НЕ дефект.** Размер сам по себе им не является; строка +- **`backend/internal/bookfile/model.go:61`=`before the reader learned to fold an uncovered leading doc` разросся до 183 строк — НЕ дефект.** Размер сам по себе им не является; строка бэклога здесь была бы трекерной инерцией. Вернётся с ценой, если заблокирует правку. **4. Находка, оказавшаяся ПОЛОВИНЧАТОЙ, и это важнее её самой.** Платформа сообщила, что §2.12 компаньона diff --git a/docs/architecture/13-tech-debt-anchors.md b/docs/architecture/13-tech-debt-anchors.md index 148dd204..c4737a19 100644 --- a/docs/architecture/13-tech-debt-anchors.md +++ b/docs/architecture/13-tech-debt-anchors.md @@ -70,7 +70,7 @@ Go-гейт стоит на v1 без поглощения кавычек: `back ### [ЗАКРЫТО D39.69 §1 + D39.71] Кандидат 73: ranked-set (инъективность рангов) -Инъективность dst построена (`membank.InjectivityCollisions`, warning-only на загрузке); типа ranked-set и проверки ПОРЯДКА ступеней из исходного обязательства (`04-unhappy-paths.md:19`=`| Коллапс терминосистемы рангов («Immortal, im`) нет. Улики с file:line — D39.66-пост-сверка (п.2). **Качество закрыто D39.69 §1, hard-режим = Q4 → D39.71 (не строить).** +Инъективность dst построена (`membank.InjectivityCollisions`, warning-only на загрузке); типа ranked-set и проверки ПОРЯДКА ступеней из исходного обязательства (`docs/architecture/04-unhappy-paths.md:19`=`| Коллапс терминосистемы рангов («Immortal, im`) нет. Улики с file:line — D39.66-пост-сверка (п.2). **Качество закрыто D39.69 §1, hard-режим = Q4 → D39.71 (не строить).** ### [ЗАКРЫТО D39.69] Кандидат 73: STITCH-ретирование инъекции отработанных термов @@ -88,7 +88,7 @@ Go-гейт стоит на v1 без поглощения кавычек: `back Команды НЕТ (⚠ список команд здесь НЕ дублируется — снятый снапшот отставал ТРИЖДЫ; единственный носитель — `backend/cmd/tmctl/main.go`, греп `dispatchCommands`, сверяйся с ним, не с этой строкой); RedriveSelector выбирает только ФЛАГНУТЫЕ чанки по chapter/chunk/reason (`backend/internal/pipeline/status.go:1078`=`RedriveSelector picks the flagged chunks` — ⚠ испр. 16.09: было :561-582), не «чанки с термом X». Источник кандидата — `docs/research/15-voice-and-state.md:201`=`одна команда ставит` (⚠ испр. 16.09: было :200): одна команда ставит until_ch=N старой записи и since_ch=N новой. При этом СУБСТРАТ построен целиком: оконные строки в схеме (UNIQUE (book_id, src, sense, since_ch, until_ch), migrate.go:202) и $0-пере-пин при bank-only-сдвиге (`backend/internal/pipeline/repin.go:14`=`POINTWISE re-edit by key`, :14-36, D39.42 п.5/D39.45) — платятся только юниты, где инъекция реально изменилась. -⚠ **Строки 73 в трекере больше нет, а этот кандидат D39.69 НЕ закрывал** — держателя, кроме этой ячейки, у него нет (смежные носители: `research/15-voice-and-state.md:200`=`2. 🧪 **NG-лексика персонажа** (5-е поле 口調表; F`, `archive/reports/BANK_QUALITY_DESIGN_2026-08-01.md`, греп `замена термина`). Скоуп при стройке — ТОНКАЯ CLI-обёртка над уже построенным (правка двух окон в сиде + штатный `repin`), не пайплайн-работа. +⚠ **Строки 73 в трекере больше нет, а этот кандидат D39.69 НЕ закрывал** — держателя, кроме этой ячейки, у него нет (смежные носители: `docs/research/15-voice-and-state.md:200`=`2. 🧪 **NG-лексика персонажа** (5-е поле 口調表; F`, `archive/reports/BANK_QUALITY_DESIGN_2026-08-01.md`, греп `замена термина`). Скоуп при стройке — ТОНКАЯ CLI-обёртка над уже построенным (правка двух окон в сиде + штатный `repin`), не пайплайн-работа. ### [ЗАКРЫТО D39.69 §1] Кандидат 86/73: feed_cap терминолога (D39.45) — «бюджет-гейт режет хвост батча» @@ -106,7 +106,7 @@ Go-гейт стоит на v1 без поглощения кавычек: `back **Р4-потолки, записанные В КОНТРАКТ правил** (двигать только замером): chevron-речь ~0.22 (24 безатрибутивные реплики офлайн неотличимы от цитат) · `minLatinResidueLen` = 3 (замер THRESHOLD=2 дал 0 изменений; гомоглиф «гy» — mixed-скрипт токен, ловится `detectBrokenWords`, не длиной) · HARD-value-чек 成/万 **не строить** (§6-Q3 → D39.79 п.4; реопен ДВУМЯ триггерами: флип hard-gate строки 12 ЛИБО ненулевой поток value-дефектов с добора идеала). ⚠ Inline-записи потолка на самих функциях НЕТ — хвост в строке 93. -**НЕ построено, диспозиции даны:** DC7 grade/role-чекер — вслепую НЕ строить, сперва $0-замер нужности на боевых финалах labels (§6-Q1 → D39.79 п.2; триггер — первая книга с живой грейд-серией) · DC2 word↔word дроби — 分之-дроби в корпусе есть (8 юнитов), размеченных дефектов класса НОЛЬ ⇒ строить вслепую — против мандата; сперва разметить 分之-срез · полный детектор повторов лемм для alignment-защиты рефренов — промпт-половина закрыта (`editor.md` + `editor-mono.md` несут исключение авторского рефрена), детектора в `checks/` нет, связка с alignment/Bertalign — строка 85. Требование защиты живо: `04-unhappy-paths.md:97`=`| **Повторы: сорный vs авторский рефрен (ритм ` («повтор в параллельных позициях оригинала = „не трогать“ … иначе редактор-агент убивает рефрены») и :130 п.5. +**НЕ построено, диспозиции даны:** DC7 grade/role-чекер — вслепую НЕ строить, сперва $0-замер нужности на боевых финалах labels (§6-Q1 → D39.79 п.2; триггер — первая книга с живой грейд-серией) · DC2 word↔word дроби — 分之-дроби в корпусе есть (8 юнитов), размеченных дефектов класса НОЛЬ ⇒ строить вслепую — против мандата; сперва разметить 分之-срез · полный детектор повторов лемм для alignment-защиты рефренов — промпт-половина закрыта (`editor.md` + `editor-mono.md` несут исключение авторского рефрена), детектора в `checks/` нет, связка с alignment/Bertalign — строка 85. Требование защиты живо: `docs/architecture/04-unhappy-paths.md:97`=`| **Повторы: сорный vs авторский рефрен (ритм ` («повтор в параллельных позициях оригинала = „не трогать“ … иначе редактор-агент убивает рефрены») и :130 п.5. **Построено, возврата не требует:** omission-бэкстоп = стеммер `declinedFormPresent` (`backend/internal/membank/mempostcheck.go`; лемма-матч {dst,decl.forms}; сам починил 2 K6-fp 凡人/甲等) — ⚠ target-алиасы к нему НЕ заведены, это сид-концерн, не код. @@ -145,7 +145,7 @@ Go-гейт стоит на v1 без поглощения кавычек: `back ### [RESCOPE ИСПОЛНЕН] (7) Протокол гендер-твиста D5.1 (дописка 49): «redrive есть, селективного by-until_ch пути нет» -Посылка «селективного пути нет» ОПРОВЕРГНУТА: селективная пере-редактура по изменению банка + смета ПОСТРОЕНЫ и живьём проверены. `backend/internal/pipeline/repin.go:14-35`=`POINTWISE re-edit by key` — «POINTWISE re-edit by key (pack-20 point 5, D39.42 п.5)»: bank-only сдвиг снапшота + неизменный content_hash → пере-пин юнита за $0, изменённые инъекции — платно; «The same predicate drives the ESTIMATE: projectRebill uses it» (смета «N units, ~$X»); встроено в штатный резюм — stagerun.go:87 (repinnable); согласие на пере-оплату — rebill.go:11-40 (D20.2-Q2). until_ch-апдейт = правка строки банка → двигается ТОЛЬКО memory_version → ровно этот путь (D39.42 п.5: «поздняя подпись и ЛЮБАЯ правка»; D39.45: «точечная ре-редактура по ключу с $0-пере-пином — построено, живьём проверено... 20 юнитов пере-пинены за $0 при bank-only-сдвиге»). При этом верно: tmctl redrive существует (`cmd/tmctl/main.go:234`=`case "redrive":`), но его селектор — только chapter/chunk/reason по ФЛАГНУТЫМ чанкам (status.go:564-582), until_ch-пути в НЁМ нет — селективность живёт в другом инструменте (translate-резюм + repin + rebill), и это by-design правильный носитель. +Посылка «селективного пути нет» ОПРОВЕРГНУТА: селективная пере-редактура по изменению банка + смета ПОСТРОЕНЫ и живьём проверены. `backend/internal/pipeline/repin.go:14-35`=`POINTWISE re-edit by key` — «POINTWISE re-edit by key (pack-20 point 5, D39.42 п.5)»: bank-only сдвиг снапшота + неизменный content_hash → пере-пин юнита за $0, изменённые инъекции — платно; «The same predicate drives the ESTIMATE: projectRebill uses it» (смета «N units, ~$X»); встроено в штатный резюм — stagerun.go:87 (repinnable); согласие на пере-оплату — rebill.go:11-40 (D20.2-Q2). until_ch-апдейт = правка строки банка → двигается ТОЛЬКО memory_version → ровно этот путь (D39.42 п.5: «поздняя подпись и ЛЮБАЯ правка»; D39.45: «точечная ре-редактура по ключу с $0-пере-пином — построено, живьём проверено... 20 юнитов пере-пинены за $0 при bank-only-сдвиге»). При этом верно: tmctl redrive существует (`backend/cmd/tmctl/main.go:234`=`case "redrive":`), но его селектор — только chapter/chunk/reason по ФЛАГНУТЫМ чанкам (status.go:564-582), until_ch-пути в НЁМ нет — селективность живёт в другом инструменте (translate-резюм + repin + rebill), и это by-design правильный носитель. **Живой остаток дописки** (пере-формулировка исполнена — строка 49 бэклога и D39.66-пост-сверка п.3): только операторский ПРОТОКОЛ-документ релиза D5.1 — последовательность «выставить `until_ch` у `gender=hidden`-терма → `tmctl translate` → согласие на rebill-смету», плюс курация 白凝冰 из строки 24. diff --git a/docs/architecture/14-api-contract/README.md b/docs/architecture/14-api-contract/README.md index ebde728e..a0a55e5c 100644 --- a/docs/architecture/14-api-contract/README.md +++ b/docs/architecture/14-api-contract/README.md @@ -365,7 +365,7 @@ drop юнит несёт причину ПЕРВОГО выпавшего чле **Окно термина (0.3.0, Б-18).** `since_chapter`/`until_chapter` стоят на НОМЕРЕ главы, а номер сам контракт называет не-ключом: нумерация плотная, правка исходника сдвигает хвост, и для книги без нумерации номера легально нет. Перевести окно на `chapter_id` нельзя — оно входит в ключ уникальности -термина у движка (`store/migrate.go:202`=`boundary is two rows with different windows`), и смена ключа это работа движка, не контракта. Поэтому +термина у движка (`backend/internal/store/migrate.go:202`=`boundary is two rows with different windows`), и смена ключа это работа движка, не контракта. Поэтому записано ЯВНО: окно живёт в координатах текущего `structure_version` и пересчитывается при его смене; два смысла нуля разведены на `null` («без границы»), потому что `Chapter.number` начинается с единицы и `0` был сентинелом с двумя значениями в двух полях. diff --git a/docs/architecture/17-seam-inbound-law.md b/docs/architecture/17-seam-inbound-law.md index 18d6f058..d6f1b280 100644 --- a/docs/architecture/17-seam-inbound-law.md +++ b/docs/architecture/17-seam-inbound-law.md @@ -60,7 +60,7 @@ не выдумывать её заново из `research/25`. 3. **Каждый JSON-выход глагола несёт версию документа — п. ИСПОЛНЕН, асимметрии нет:** `tm-bank-v1` - (`pipeline/bankexport.go:30`=`const bankExportVersion = "tm-bank-v1"`), `tm-manifest-v2` (`pipeline/manifest.go:46`=`const manifestVersion = "tm-manifest-v2"`) + (`backend/internal/pipeline/bankexport.go:30`=`const bankExportVersion = "tm-bank-v1"`), `tm-manifest-v2` (`backend/internal/pipeline/manifest.go:46`=`const manifestVersion = "tm-manifest-v2"`) и `status --json` (`backend/internal/pipeline/status.go:173`=`const statusVersion = "tm-status-v1"`, проставляется `:485`). 4. **Незнакомый флаг = громкий отказ при спавне.** Сегодня это так по устройству разбора аргументов diff --git a/docs/architecture/18-bank-ontology.md b/docs/architecture/18-bank-ontology.md index d5e3a98c..ff13ed73 100644 --- a/docs/architecture/18-bank-ontology.md +++ b/docs/architecture/18-bank-ontology.md @@ -18,7 +18,7 @@ | Роль | Носители | Писатель | Момент фиксации | |---|---|---|---| -| **ИСТОЧНИКИ** — то, из чего банк собирается | `glossary_seed` · `.mined-delta.yaml` · `.mined-rejects.yaml` (слово ВЛАДЕЛЬЦА, рядом с `book.yaml`, едут с книгой в бэкапе и экспорте) · `.auto-bank.yaml` (слово ДВИЖКА, сидит при базе) · ruby-чтения в хранилище | у каждого РОВНО один. ⚠ Дверь `bank-apply` пишет ТОЛЬКО два файла решений: правка сид-терма ею ОТКЛОНЯЕТСЯ по имени (`internal/membank/decisions.go:359`=`Scoped to APPROVE`), потому что это перенос базового снапшота и пере-оплата черновой волны — другое решение (щель ратифицирована, строка 192). `glossary_seed` — рука владельца · `auto-bank` — прогон · ruby — хранилище | запись двери — под эксклюзивным флоком проекта; рука владельца флока не берёт (остаток — строка 222) | +| **ИСТОЧНИКИ** — то, из чего банк собирается | `glossary_seed` · `.mined-delta.yaml` · `.mined-rejects.yaml` (слово ВЛАДЕЛЬЦА, рядом с `book.yaml`, едут с книгой в бэкапе и экспорте) · `.auto-bank.yaml` (слово ДВИЖКА, сидит при базе) · ruby-чтения в хранилище | у каждого РОВНО один. ⚠ Дверь `bank-apply` пишет ТОЛЬКО два файла решений: правка сид-терма ею ОТКЛОНЯЕТСЯ по имени (`backend/internal/membank/decisions.go:359`=`Scoped to APPROVE`), потому что это перенос базового снапшота и пере-оплата черновой волны — другое решение (щель ратифицирована, строка 192). `glossary_seed` — рука владельца · `auto-bank` — прогон · ruby — хранилище | запись двери — под эксклюзивным флоком проекта; рука владельца флока не берёт (остаток — строка 222) | | **ВИД** — банк, каким его видят роли | строки глоссария в хранилище | только `seedGlossary`, и только полным пересбором | каждая граница прогона; один загрузчик, все гарды | | **ПРОЕКЦИИ** — то, что банк рассказывает наружу | `.bank.json` (единственный канал банка наружу) · карта подписи `.mined-signature.yaml` · человеческая таблица стопа `.bank-stop.txt` | прогон, на границе | ⚠ не одинаков: `bank.json` — ПОСЛЕ смены вида; карта подписи и `.bank-stop.txt` — при вычислении стопа, ДО пере-сида, а на стоп-границе вид вообще не меняется (остановившийся прогон авто-банк не пишет) | | **ПАМЯТЬ ФЛАЖКА** — что стоп уже предъявлял | таблица `bank_stop_presented` | стоп | ПОСЛЕ карты, никогда до | diff --git a/docs/product-requirements.md b/docs/product-requirements.md index 20f991fc..74298dab 100644 --- a/docs/product-requirements.md +++ b/docs/product-requirements.md @@ -54,7 +54,7 @@ | ID | Требование (источник) | Статус | Носитель / доказательство | |---|---|---|---| | ПТ-20 | Ридер-IDE: VS Code-подобный фронт агентного перевода (V0-п.20/23) | ⭕ | research/16 принят (D29); строки 69–71; F3-brief — D29 п.3. Ф3 ОТКРЫТА 02.08 (D39.81): фронт-сессия живёт на моках; контракт API ратифицирован (D39.99; ⚠ версию канона брать ФАЙЛОМ, не этой ячейкой — норма и команда в карте `README.md`. Открытыми по контракту остаются хвост строки **203** и строка **241** — самопротиворечие канона на дочитанной книге.); платформа построена до читающей поверхности и денежной двери (паки P0…P13 — реестр нот; ⚠ КВОТ нет ни строки кода, и по D39.176 п.1 не будет — продуктовых квот нет, фри-тир-лимиты не проектируются; ретеншен/свип остаются инженерной гигиеной); фронт — S0–S4 приняты, **зона ЗАМОРОЖЕНА** (D39.136 п.2 + D39.147: сначала движок и платформа до «работает и отдаёт результат», фронт накручивается на готовую функциональность) | -| ПТ-21 | Параллельное чтение двух текстов с выравниванием по смыслам (V0-п.21); выравнивание грубое, по единицам экспорта — принято владельцем 02.08, спаны внутри текста не строятся | 🔶 | механизм готов: `tmctl export --pairs` выравнивает пары побайтно по единицам редактуры (`internal/pipeline/export.go:149`=`aligned byte-for-byte`); якорь = **edit-unit**, НЕ чанк (переформулировано D39.84 — финальный текст существует только на уровне юнита, ~1.9 юнита/главу, местами глава = один блок; читалка обязана это выдерживать); UI-читалка = Ф3 (этап S6) | +| ПТ-21 | Параллельное чтение двух текстов с выравниванием по смыслам (V0-п.21); выравнивание грубое, по единицам экспорта — принято владельцем 02.08, спаны внутри текста не строятся | 🔶 | механизм готов: `tmctl export --pairs` выравнивает пары побайтно по единицам редактуры (`backend/internal/pipeline/export.go:149`=`aligned byte-for-byte`); якорь = **edit-unit**, НЕ чанк (переформулировано D39.84 — финальный текст существует только на уровне юнита, ~1.9 юнита/главу, местами глава = один блок; читалка обязана это выдерживать); UI-читалка = Ф3 (этап S6) | | ПТ-22 | ⚠ **испр. 05.09: жанровый словарь ОТМЕНЁН как класс (`D39.47`, 26.07), а ПОЛЕ `genre` выкинуто из продукта вайр-батчем и отставка прибита тестом (`D39.195` п.2, греп `genre_retired_test.go`) — два РАЗНЫХ решения, прежняя редакция их смешивала и ссылалась на `D39.104` п.2, которая про единый закон-блок, строка 184 ЗАКРЫТА лендингом вайр-батча — предстоящей работы здесь нет.** Настройки от человека: 18+, жанр и т.п. (V0-п.22) | 🔶 | `book.yaml` (labels) данными; UI = Ф3. ⚠ ЖАНР из продукта ВЫКИНУТ словом владельца 16.08 (D39.138 п.2в, строка 184: ни на чём не ветвится, влияние не измерено; снимается из промптов/брифа/контракта/формы) | | ПТ-23 | Веб-ПЕРВЫЙ фронт; SEO/ранжирование Google — куки, страницы-сироты, актуальные алгоритмы (V5-п.2); продукт = **SaaS**, не локальное приложение (решение владельца 02.08, D39.81 — натив-прицел V0-п.26 СНЯТ этим решением, вернуть только новым словом владельца); SEO только под Google, Яндекс снят; рынок глобальный; десктоп = PWA первым шагом, Tauri по явным триггерам (решения владельца 02.08, D39.84) | ⭕ | строка 71 (Ф3-бриф); SEO вошёл в стек-дизайн ДО выбора (D39.84, требование исполнено): двухконтурный деплой — SPA `app.<домен>` целиком под noindex + статический публичный контур ≤3 кликов от главной (лечение страниц-сирот), `frontend/docs/STACK_DECISIONS.md` §4; SSR-вопрос закрыт этим решением | | ПТ-24 | Цикл согласования глоссария с профпереводчиком/редактором (V0-п.23) | 🔶 | подписной цикл терминолога в бэкенде есть; UI = Ф3. Модель цикла записана словом владельца 16.08 (D39.144 + строка 192): черновой перевод и черновой банк появляются вместе → ОДИН ОК всему банку (не пер-термная масс-подпись) → доработка → пост-ридинговые точечные правки с пере-генерацией по вхождениям (механика — после полигона) |