diff --git a/docs/BACKLOG.md b/docs/BACKLOG.md index d002b4c3..ffe42a8d 100644 --- a/docs/BACKLOG.md +++ b/docs/BACKLOG.md @@ -215,7 +215,7 @@ | 280 | ✅ **ИСПОЛНЕНО ЛЕНДИНГОМ 06.09 — акт `D39.208`.** Заказ живёт на КНИГЕ и хранится ИДЕНТИЧНОСТЬЮ (`books.ordered_through_chapter_id`), а не ординалом; холд считается от проекции движка; `--max-units` едет в argv. ⚠ **Кроме ОДНОЙ позиции, от которой зона отказалась с доводом и которая живёт отдельно:** денежный ползунок объявлен на проводе, но отправить его нечем, и оценки под ВЫБРАННЫЙ заказ нет. Прежняя редакция ряда: **ШАГ 4, ПЛАТФОРМА: заказ живёт на КНИГЕ, холд считается от проекции, `--max-units` наконец едет в argv.** `books.ordered_through_chapter` (null = вся книга) — сегодня интент живёт на ПРОГОНЕ, оттого и неловкость «поднять лимит = НОВЫЙ прогон с бо́льшим `ceiling_chapters`»; с заказом на книге «Продолжить» после пополнения тривиален, и дверь пере-прохода встаёт рядом вторым типом заказа. Холд = `min(баланс, проекция × k)`; `bookCap = committed + холд` (`PD-158` цел). В argv добавляется `--max-units` = сумма юнитов заказанных глав минус доставленные. Удаляются `DefaultPerChapter`, `Scale` и `draftWork`: план движка становится РАВЕН заказу, и «черновики на весь потолок при нуле готовых глав» исчезает структурно. Закрывает `PD-410`, `PD-440`, `PD-446`. ⚠ **ПРЕДУСЛОВИЕ, названное отдельно: `PD-422`** — `--resnapshot` передаётся УСЛОВНО, а условие ставит только правка банка; рост авто-банка от майнинга флага не ставит. Частичный заказ на майнящей книге растит банк ⇒ следующий заказ без `--resnapshot` умрёт на снапшот-гарде, холд взят, попытка сожжена. Взять В ТОТ ЖЕ пак | платформа | скоро | заказ на книге + холд от проекции + проводка `--max-units` + PD-422 | согласование 04.09 | | 281 | **ЗАМЕР: сколько наших денег стоит тысяча ПЛОТНЫХ и тысяча РАЗРЕЖЕННЫХ знаков по стадиям и парам.** Цель — НЕ константа (D39.165 п.1г прямо запрещает ставку константой), а **дисперсия проекции**: коэффициент k для холда и честность вердикта «хватит ли». Снимать есть из чего и это $0: `find -L books` даёт 162 базы прогонов, в `request_log` лежат `chapter · chunk_idx · stage · prompt/completion_tokens · cost_usd · tm_hit`, исходник по юниту отдаёт `tmctl export --pairs` бесплатно. Метод: по юниту плотные/разреженные знаки против суммы `cost_usd` при `tm_hit=0`, по стадиям; хвост ретраев и эскалаций считать ОТДЕЛЬНО; базы до 16.08 пере-прайсить по токенам. ⚠ Гейт для коэффициента холда в строке 280 | полигон | скоро (гейт строки 280) | замер по 162 базам, $0 | согласование 04.09, вторая редакция | | 282 | ⛔ **ЧИСЛО, ПОДПИСАННОЕ «ЗНАКОВ», СЧИТАЕТ РУНЫ ПОТОКА ЗАПИСИ ФАЙЛА — что для UTF-8 txt И ЕСТЬ знаки, а для EPUB даёт руны ZIP-АРХИВА.** ⚠ Заголовок первой редакции («считает байты») — противоположная полуправда, испр. 05.09: ложно оно для EPUB, GB18030 и UTF-16, а не всегда. Проверено оркестратором по коду: `platform/internal/books/books.go`, греп `type counter` — счёт идёт по не-продолжающим байтам UTF-8 ПОТОКА ЗАПИСИ файла, а не по тексту; там же комментарий признаёт приближение для GB18030. Наружу уходит как `character_count` (`platform/internal/httpapi/v0.go`), на экране подписано `'about.characters': 'Знаков'` (`frontend/src/i18n/ru.ts`). ⇒ Живая ложь на продуктовом экране, и она же — вторая ненадёжная единица, найденная тем же вопросом «откуда берётся число». **Основой страницы быть не может.** Лечение: переименовать в размер файла ЛИБО заменить манифестной суммой знаков движка — ✅ **источник ПОСТРОЕН**: `source_chars` по юниту в `manifest --json` (лендинг `81a89e9`, акт D39.206; строка 278 закрыта и снята). ⛔ **ПЛАТФОРМЕННАЯ ПОЛОВИНА ИСПОЛНЕНА (пере-снято 06.09 по коду, не по комментарию):** число берётся из манифеста движка — `platform/internal/httpapi/project.go:39`=`out.CharacterCountExact` (⚠ испр. 17.09: было :38), рядом с ним флаг точности в `platform/internal/httpapi/v0.go:216`=`CharacterCountExact bool` (⚠ испр. 17.09: было :211), пин `v0_test.go:933`. Остаток строки — ТОЛЬКО подпись `'about.characters': 'Знаков'` во фронте, а зона фронта ЗАМОРОЖЕНА ⇒ строка ждёт разморозки и в платформенные паки больше не входит | фронт | скоро (первое касание при разморозке) | снять ложную подпись `'about.characters'` во фронте (источник уже манифест движка — половина исполнена) | согласование 04.09; проверено оркестратором по коду | -| 283 | **СТРУКТУРА ГЛАВ ДЛЯ ВЫДАЧИ — отдельная задача, которую «страница» НЕ отменяет, и она гейтит бету для не-CJK и EPUB.** Билдер кладёт по одному XHTML на главу движка и сам признаёт, что ридер делает главу из каждого документа spine (`backend/internal/bookfile/epub.go`) ⇒ **для не-CJK txt читатель получает книгу ОДНИМ ПОЛОТНОМ при любой единице заказа**. Состав — этап 1 `research/27`: EPUB по nav/NCX (обязательно по стандарту), FB2, индуктор оглавления для txt, разрез по ДАННЫМ ПАРЫ вместо захардкоженного CJK (сегодня асимметрия: распознавание строки-заголовка данные пары читает — `configs/langpacks/zh-ru/heading.txt`, — а РАЗРЕЗ на главы нет). ⚠ Делать в единственном окне пере-снапшота, пока платная книга одна: перекрой двигает нарезку. Пере-скоуп строк 160–162 | бэкенд | скоро (ДО открытия беты не-CJK и EPUB-входам) | этап 1 research/27 своим паком | согласование 04.09, вторая редакция | +| 283 | **СТРУКТУРА ГЛАВ ДЛЯ ВЫДАЧИ — отдельная задача, которую «страница» НЕ отменяет, и она гейтит бету для не-CJK и EPUB.** Билдер кладёт по одному XHTML на главу движка и сам признаёт, что ридер делает главу из каждого документа spine (`backend/internal/bookfile/epub.go`) ⇒ **для не-CJK txt читатель получает книгу ОДНИМ ПОЛОТНОМ при любой единице заказа**. Состав — этап 1 `research/27`: EPUB по nav/NCX (обязательно по стандарту), FB2, индуктор оглавления для txt, разрез по ДАННЫМ ПАРЫ вместо захардкоженного CJK (сегодня асимметрия: распознавание строки-заголовка данные пары читает — `configs/langpacks/zh-ru/heading.txt`, — а РАЗРЕЗ на главы нет). ⚠ Делать в единственном окне пере-снапшота, пока платная книга одна: перекрой двигает нарезку. Пере-скоуп строк 160–162 ⭐ **ЧИСЛА НА БОЕВОЙ АНГЛИЙСКОЙ КНИГЕ, замер зоны 18.09 — предмет ряда впервые получил величину.** Книга Кристоффа режется движком на **71 «главу», из которых настоящих ШЕСТЬ** (`BOOK ONE`…`BOOK SIX`, 140–390 тыс. знаков), одна средняя и **64 КРОШЕЧНЫЕ — это страница «Contents», разрезанная конвертером на файлы по одной строке**; детерминированный заголовок непуст у **0 из 71**. Проекция цены всей книги $6.65, из них на 64 осколка **$0.38**. ⇒ ряд перестал быть теоретическим: не-CJK книга платит за оглавление как за главы. ⚠ Механизм группировки документов в коде ЕСТЬ (`backend/internal/chunk/epubtoc.go:293`=`func groupChapters`, привязывает неграничный документ к предыдущей главе) — значит вопрос не «построить», а «почему 64 осколка прошли как границы»; это и есть предмет замера перед стройкой. | бэкенд | скоро (ДО открытия беты не-CJK и EPUB-входам) | этап 1 research/27 своим паком | согласование 04.09, вторая редакция | | 284 | **НАЗВАНИЕ КНИГИ И ЗАГОЛОВКИ ГЛАВ ИДУТ ЧЕРЕЗ ТЕРМИНЫ — ОТДЕЛЬНОЙ СТАДИЕЙ (решение владельца 05.09).** ⚠ **СЮДА ЖЕ ПЕРЕЕХАЛ ОСТАТОК ЗАКРЫТОЙ СТРОКИ 274 (D39.201 п.7): доставка имени В ФАЙЛ.** Платформенная половина построена — имя вычисляется ПРИ СКАЧИВАНИИ (`platform/internal/httpapi/v0.go`, греп `exportName`), внутрь файла не пишется намеренно: движок сворачивает `title` в `BriefHash` → снапшот → каждый request-hash, то есть запись в `book.yaml` отказала бы следующему прогону недопереведённой книги и стоила бы ПЕРЕ-ОПЛАТЫ книги целиком. **ФОРМА ОПИСАНА, ПАТЧ НЕ ПРОВЕРЕН** (слово платформенной зоны, принято дословно): путь — `tmctl build --title` аргументом при спавне, прецедент `--ceiling-usd`, но НЕ предъявлено исполнением, что движок примет незнакомый флаг без правки разбора аргументов — по закону шва там громкий отказ по построению. Остаток регистра — `PD-450`. Сегодня их не переводит НИКТО: `dc:title` берётся из `book.yaml` как есть (`backend/internal/bookfile/epub.go`, греп `dc:title`), заголовок главы собирается детерминированно шаблоном из langpack (`backend/configs/langpacks/zh-ru/heading.txt`, `template Глава {n}`). ⇒ Русский EPUB приезжает в читалку с китайским названием — ломается первое, что видит человек. Владелец: «пусть едет как термины, причём отдельные, то есть как-то надо называть эту стадию». ⚠ Значит у стадии своё имя, свой бюджет и своя ПОДПИСЬ: название книги владелец утверждает так же, как утверждает термин. ✅ **ПОДПИСЬ РЕШЕНА ВЛАДЕЛЬЦЕМ 11.09, и она НЕ отдельный узел:** «это идет банком и делается автоподпись\подпись юзера просто, вот и все» ⇒ заголовки и название едут через БАНК ПАМЯТИ тем же механизмом подписи, каким подписывают термины; проектировать под них собственный узел подписи НЕ надо. ⚠ Родня — строка 274 (ручка переименования у пользователя) и открытый лист владельца «что печатать на титуле и в имени файла» (D25.1): механизм строится, СЛОВО остаётся за владельцем | бэкенд | скоро | стадия перевода заголовков, подпись — БАНКОВСКАЯ (авто либо пользовательская) | решение владельца 05.09, подпись решена 11.09 | | 286 | ⚠ **ЧИТАТЬ ЧЕРЕЗ `D39.205`: стоп остаётся ЦЕЛЬЮ, но гейт `gates.glossary.postcheck_gate` владелец 05.09 ОТЛОЖИЛ до замера точности («Не знаю. Тут надо мерить типо?… ложные срабатывания — это плохо, очень плохо») — это отсутствие замера, а не запрет** («ложные срабатывания — это плохо, очень плохо»); предусловие — строки 295 и 12. ⚠ **Сюда же перенесён 06.09 «ДЕТЕКТОР ВЕРНОСТИ ЗНАЧЕНИЯ» из строки 318** — четвёртым носителем одного вопроса он был бы трекерной инерцией: прибор, проверяющий вложенный `dst` ПО ИСХОДНИКУ, — тот же самый, что линза строки 319 после починки, а $0-прототип уже назван строкой 12. ⇒ **строка 318 остаётся только конкретной правкой** (комментарий постчека привести к поведению плюс пин), а вопрос «чем ловить неверное ЗНАЧЕНИЕ» живёт здесь и упирается в замер точности, а не в код. ⛔ **ПРИОРИТЕТ №1 ВЛАДЕЛЬЦА («100% консистентность») НЕ ИСПОЛНЯЕТСЯ КОДОМ И ПРОТИВОРЕЧИТ ДЕЙСТВУЮЩЕМУ ПОРОГУ.** Найдено ревизией документации 05.09. Три расхождения, каждое с носителем: **(1) ПОРОГ.** `docs/architecture/02-mvp-plan.md` и реестр `D10` держат «≥98%» — владелец 05.09 сказал **100%** (`D39.198`). Два процента на книге в тысячи терминов — это десятки разъехавшихся имён. **(2) МЕХАНИЗМ.** Единственный сегодняшний носитель консистентности — флаг `glossary_miss` РАНГА 5, то есть замечание, **с которым текст ОТГРУЖАЕТСЯ** (`backend/internal/pipeline/status.go` + `disposition.go`, греп `FlagGlossaryMiss`). Владелец сказал «разъехавшийся термин — СТОП». Флаг стопом не является. **(3) СЕМАНТИКА.** Приоритет №2 («никаких выдуманных сюжетных линий и смыслов») не имеет носителя вовсе: в реестре требований такого ПТ нет, ближайшее — гейт по ДЛИНЕ, а не по смыслу; семантический судья в движке не построен (слой 5). ⇒ **Сессия качества, собранная по нынешним докам, построит от неверной цели.** ⚠ Родня: строка **267** (две конкурирующие формы одного термина доезжают до редактора) — она и есть живой экземпляр нарушения приоритета №1 | бэкенд+полигон | скоро | порог 100% в носителях · консистентность как СТОП, а не флаг · носитель для приоритета №2 | ревизия документации 05.09, `D39.198` | | 287 | **ТЕСТ ИСЧЕРПАЕМОСТИ ФЛАГОВ СЛЕП НА ТРЕТЬЮ ЛЕГАЛЬНУЮ ФОРМУ Go — найдено ПОСАДКОЙ верификатора приёмки, не автором.** Тест читает объявления причин через `go/ast` и покрывает две формы (`X FlagReason = "…"` и `X = FlagReason("…")`), о чём говорит его собственный комментарий «BOTH GO SPELLINGS COUNT». Третья форма — типизированная спека со значением-конверсией (`const X FlagReason = FlagReason("…")`) — **ПЕРЕЖИВАЕТ посадку**: типизированная ветка ждёт `*ast.BasicLit`, получает `CallExpr`, `lit == nil` и молча продолжает. Пол `found < 15` её тоже не ловит. ⚠ **Это ГРАНИЦА, а не живая дыра:** ни одной такой формы в дереве сегодня нет (все константы в `disposition.go` типизированные) — но комментарий обещает больше, чем тест держит, а это тот самый класс «утверждение шире ветки», который пак ловил четырежды. Там же не назван и `var`-случай. | бэкенд | когда-нибудь | покрыть третью форму ЛИБО сузить комментарий до двух | верификатор приёмки 05.09, посадка вне списка автора | @@ -405,7 +405,7 @@ | 495 | ⛔ **РЕШЕНИЕ ВЛАДЕЛЬЦА О РОДОВОЙ ДИРЕКТИВЕ ЗАПИСАНО В ЖУРНАЛЕ И НЕ ИСПОЛНЕНО В ДАННЫХ — носителя у него не было вовсе.** `backend/internal/lang/data/injection.txt:12` по-прежнему предписывает роли «при неизбежности — мужские», тогда как `D39.254` п.3 постановил «меняется ТОЛЬКО текст данных `injection.txt:12`: вместо «при неизбежности — мужские» — перестроить фразу, а если литературно не выходит, писать как читается лучше», и `D39.263` п.2 уже ОБЪЯВИЛ это исполненным («больше не предписывает»). ⚠ **Замер 17.09 с контролем:** строка в дереве жива (1 совпадение), упоминаний `injection.txt` в журнале решений **4**, рядов трекера на этот предмет — **0**. ⇒ решение существовало только в прозе ратификаций, а гейт чисел такого не видит по построению: он сторожит литералы, а не согласие решений с деревом. ⛔ **И это НЕ «правка данных за $0».** Файл встроен `go:embed` (28 упоминаний в `backend/internal/lang/embedded.go`), а `lang.EmbeddedVersion()` хеширует встроенные файлы целиком (`backend/internal/lang/embedded.go:79`=`hashEmbeddedFiles`) ⇒ хеш двигает тег кроя и ключ манифеста, у купленной книги стираются `unit_resolutions` платформы и пере-покупается нарезка. ⇒ правка идёт в ОКНО ПЕРЕКРОЯ вместе со свёртками исходника (ряд **446**) и ручкой голоса (ряд **410**); окно открыто словом владельца 17.09 и закрывается первым же продолжением книги. ⚠ Класс для следующей смены: **ратифицированное без носителя исполняется ноль раз, и вторая нота, объявившая исполнение, лжи не заметила** — акт судил намерение, а не дерево | бэкенд | скоро (в окне перекроя) | `injection.txt:12` не предписывает род по умолчанию, формулировка ратифицирована, и правка уехала ОДНИМ заходом со всеми прочими правками встроенных данных | верификация актов Fable 5 17.09, пере-снято оркестратором | | 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, брать медиану) либо нормировать на опорный замер той же секунды — тогда общая нагрузка сокращается по-настоящему, а не по предположению. ⚠ Родня ряда про «пин, флейковый на мутанте, измеряет пустой сценарий», но здесь хуже: флейк на ЗДОРОВОМ дереве | бэкенд | скоро | пин краснеет только на настоящей квадратичности: посадка «вернуть квадратичный `window()`» краснеет им, а десять прогонов полной батареи подряд — зелёные | найдено `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; все пять адресов пере-проверены оркестратором | | 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 отказах по балансу на английской оси |