diff --git a/docs/BACKLOG.md b/docs/BACKLOG.md index 0c6f03f3..96a2565c 100644 --- a/docs/BACKLOG.md +++ b/docs/BACKLOG.md @@ -410,4 +410,4 @@ | 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 отказах по балансу на английской оси | | 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/` не трогала. **Первый свидетель 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`, оба на пакете, который ни одна не трогала | +| 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`, оба на пакете, который ни одна не трогала |