diff --git a/docs/BACKEND_FAILURE_YOU_CAN_SEE_SESSION_PROMPT.md b/docs/BACKEND_FAILURE_YOU_CAN_SEE_SESSION_PROMPT.md index e892a87f..bb4527b7 100644 --- a/docs/BACKEND_FAILURE_YOU_CAN_SEE_SESSION_PROMPT.md +++ b/docs/BACKEND_FAILURE_YOU_CAN_SEE_SESSION_PROMPT.md @@ -134,6 +134,24 @@ | **размышление съело потолок** | 2-я попытка дала МЕНЬШЕ, чем потолок 1-й (`edit`: 11717 < 16000) | удвоить — то есть дать размышлению вдвое больше места | **ступень эффорта ниже при ТОМ ЖЕ потолке** — но см. ⛔ ниже, величина не замерена | | `length` **с текстом** | обрезок доехал | удвоить | **оставить как есть** — это ровно решение `D2` | +⛔⛔ **ДВЕ ПОПРАВКИ К ТАБЛИЦЕ, СНЯТЫЕ ЗАМЕРОМ 11.09 — читай их прежде, чем исполнять её.** + +**(а) «Ступень эффорта ниже» СЕГОДНЯ ВЫРОЖДЕНА НА ВСЕХ БОЕВЫХ ЗНАЧЕНИЯХ.** Замер: во всех четырёх живых +`configs/pipeline-*.yaml` значений `reasoning:` **двенадцать**, и все — `low` (7) или `off` (5). Словарь +движка упорядочен `"" · off · low · medium · high` (`ValidReasoningEffort`), и **ниже `low` эмитирующей +ступени НЕТ**: `off` и пустая строка не эмитят ничего, то есть едет вендор-дефолт `high` — это БОЛЬШЕ +размышления, а не меньше. ⇒ шаг вниз по нейтральному словарю на сегодняшнем конфиге некуда сделать. +Носитель дорогого случая (`edit`) стоит именно на `off`. **Из трёх законных выходов §4.1 первый +(«шаг вниз по нейтральному словарю») снимается как вырожденный**, пока боевые значения такие; остаются +второй (решать через оценку первого потолка) и третий (пер-модельная таблица — только пингом до кода). + +**(б) ОДНА ЕДИНИЦА ПРОГОНА ПОПАДАЕТ В ДВЕ СТРОКИ ТАБЛИЦЫ СРАЗУ, и приоритета в ней не было.** +`draft` ch2u1 (`degraded='length'`, обрезок с текстом, ретрай дал **13004 > 8496**) удовлетворяет и строке +«потолок мал» (2-я попытка больше потолка 1-й), и строке «`length` с текстом → оставить как есть». ⇒ +**приоритет задаю: строка «`length` с текстом» применима ТОЛЬКО если ретрай уложился в СТАРЫЙ потолок.** +Не уложился — значит потолка и вправду не хватало, и побеждает первая строка. Иначе единственный носитель +третьей строки уходит в неё же и класс остаётся непроверяемым. + ⛔ **ЧЕГО В ТАБЛИЦЕ НЕТ И НЕ ДОЛЖНО БЫТЬ: «не перевыпускать».** На замеренных данных это стоило бы трёх восстановленных чанков из четырёх и отменяло бы `D2` п.2. Вопрос — в ЦЕНЕ попытки, а не в её отмене. @@ -170,6 +188,11 @@ a named finding, not a silent gap». ⇒ **пер-модельная табли `reasoning_effort`; ничего не эмитят только `off` и пустая строка, и тогда едет вендор-дефолт `high`. Именно `off` стоит у редактора в `backend/configs/pipeline-c1.yaml` — **это ВЫБОР конфига, а не невозможность.** Проверь чтением `internal/llm/capability.go` сама. +⛔ **И ПРЕЖДЕ ЧЕМ ЧИТАТЬ БОЕВОЙ КОНФИГ — он несёт ОТОЗВАННЫЙ вендорский клейм.** + `backend/configs/pipeline-c1.yaml:86`=`v4-pro maps low` дословно: «v4-pro maps low→high, effective effort + unchanged». Это было верно до 30.08 и ОТОЗВАНО квирками: вендор сменил маппинг, и `low` на `pro` теперь + даёт `low`. Комментарий в дереве живёт, читатель ему верит. **Носитель поправки — ряд бэклога 429**; + правка самого комментария в твоём паке НЕ заказана, но не наследуй его как факт. * **«На pro рычага нет» больше не правда.** Вендор сменил маппинг; полигон снял поведенческую пробу 30.08 за $0.038276 и показал, что `low` до `pro` доходит. Живая запись — квирки §3г. * ⇒ **ось «`off` против `low`» измеряется ОТДЕЛЬНЫМ КОНФИГОМ КНИГИ. Это ДАННЫЕ**: ни правки Go, ни снятия @@ -189,9 +212,9 @@ a named finding, not a silent gap». ⇒ **пер-модельная табли ### 4.3. `reasoning_tokens` не несла числа ни разу · «реши сама и аргументируй» -Замер оркестратора 11.09: `request_log.reasoning_tokens > 0` — **0 строк**. Контроль рядом: найдено -**448** файлов `*.db`, таблицу `request_log` несут **405**, прочитано **58 886** строк, колонка объявлена -схемой и присутствует во всех. ⇒ единственная колонка, которой доказывают «потолок съело рассуждение», +Замер оркестратора 11.09: `request_log.reasoning_tokens > 0` — **0 строк**. Контроль рядом: найдено **449** файлов `*.db`, прочитано **58 886** +строк-экземпляров, и ⛔ **уникальных из них 5 413** — свод обходом диска умножает счёт на число копий базы +в **10.88** раза (ряд **428**); ноль устоял и на честном знаменателе. Колонка объявлена схемой и присутствует во всех. ⇒ единственная колонка, которой доказывают «потолок съело рассуждение», структурно молчит, и её ноль неотличим от «рассуждения не было». Причина известна и не баг нашего кода: DeepSeek считает рассуждение внутри `completion_tokens` и отдельным @@ -218,11 +241,14 @@ a named finding, not a silent gap». ⇒ **пер-модельная табли ### 4.5. Цена считается по модели, которой нет в каталоге · «делай РОВНО так» в части замера, «реши сама» в части лечения -Замер оркестратора 11.09 по всем базам машины (контроль: 448 файлов `*.db`, 405 с `request_log`, 58 886 -строк): **365 строк оплачены ПОДСТАНОВКОЙ** — провайдер вернул слаг, которого в каталоге нет. ⚠ Из них -**344 боевые** (`deepseek-v4-flash` → `deepseek-flash`, 296 строк, $2.049737; `local-qwen3-8b` → -`huihui_ai/qwen3-abliterated:8b`, 48 строк, $0) и **21 — тестовые фикстуры** (`m-req`→`m-act`, -`fake-model`), которые обязаны быть вычтены: иначе $5.51 фикстуры уедут в денежный вывод. +Замер оркестратора 11.09, пере-снятый 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» — это моя +протухшая редакция, не наследуй её. **Сегодня это безвредно:** подстановка падает на ЗАПРОШЕННУЮ модель той же семьи. ⛔ Опасна не подстановка, а её молчание. `PriceForResponse` (`internal/ledger/pricing.go:61`=`func (p *Pricer) PriceForResponse`) пробует `actual`, потом `requested`, diff --git a/docs/BACKLOG.md b/docs/BACKLOG.md index 572f11ac..c5a2da35 100644 --- a/docs/BACKLOG.md +++ b/docs/BACKLOG.md @@ -3,7 +3,7 @@ > **Единственный трекер проекта.** Здесь живут строки, на которые доки, промты и D-ноты ссылаются словами «строка N» / «строка бэклога N»: **ID строки стабилен навсегда**, не перенумеровывается и не переиспользуется (D39.80). Правки — только через оркестратора; каждая петля обязана иметь диспозицию: решено / отложено-с-записью / отклонено. > ⚠ **Это НЕ бэклог зоны `docs/`, а бэклог ПРОЕКТА.** У зон свои, с другими неймспейсами ID, и единый их строк не принимает (D39.84): платформа — [../platform/BACKLOG.md](../platform/BACKLOG.md) (`П-N`) и её регистр дефектов `platform/docs/DEFECT_REGISTER.md` (`PD-N`); фронт — [../frontend/docs/BACKLOG.md](../frontend/docs/BACKLOG.md) (`Ф-N`). > ⚠ **Состояние проекта — не здесь.** Очередь, курс, CURRENT-STATE, состояние паков и живая хроника — шапка [PROGRESS.md](PROGRESS.md). Здесь только долг и его диспозиции. -> - **СЧЁТ ОЧЕРЕДИ на 11.09 (скриптом по таблице — `python3 docs/scripts/counts.py`; обновлять при каждом лендинге):** всего **312** строк · зона бэкенд **150** строго / **204** широко (⚠ колонки счётчик читает С КОНЦА — испр. D39.116) · **блокеров очереди 0** (236 закрыта D39.175; **371** — актом D39.233, **360** — актом D39.232, обе 10.09), платные прогоны разблокированы · «скоро» **157** (перечень — грепом по таблице, рукописный список снят D39.126) · гейт-строка эксп-22: 153 (плюс 150 — руки владельца; ⚠ 55 из гейтов СНЯТА — D39.198 п.5); строка 5 — остаток гейчен ре-пробой 74, носитель события теперь строка 188 (аудит D39.140); остальное «когда-нибудь». ⚠ Счёт — НИЖНЯЯ граница долга, не потолок (разбор — легенда таблицы ниже). +> - **СЧЁТ ОЧЕРЕДИ на 11.09 (скриптом по таблице — `python3 docs/scripts/counts.py`; обновлять при каждом лендинге):** всего **313** строк · зона бэкенд **151** строго / **205** широко (⚠ колонки счётчик читает С КОНЦА — испр. D39.116) · **блокеров очереди 0** (236 закрыта D39.175; **371** — актом D39.233, **360** — актом D39.232, обе 10.09), платные прогоны разблокированы · «скоро» **158** (перечень — грепом по таблице, рукописный список снят D39.126) · гейт-строка эксп-22: 153 (плюс 150 — руки владельца; ⚠ 55 из гейтов СНЯТА — D39.198 п.5); строка 5 — остаток гейчен ре-пробой 74, носитель события теперь строка 188 (аудит D39.140); остальное «когда-нибудь». ⚠ Счёт — НИЖНЯЯ граница долга, не потолок (разбор — легенда таблицы ниже). > - ⚠ **Переезд 06.09 (D39.218):** таблица вынесена из `PROGRESS.md` ДОСЛОВНО и ни один ID не сдвинут — **с единственным исключением: две ячейки (строки 220 и 306) тронуты РОВНО в номере якоря `docs/scripts/counts.py:566`→`:569` и `:592`→`:595`**, потому что цель сдвинул этот же коммит; текст ячеек не менялся, длины равны. В `PROGRESS.md` на прежнем месте оставлен заголовок-указатель, поэтому ссылки «секция „Бэклог“» доезжают в один хоп. ## Бэклог (ЕДИНЫЙ, собран 26.07, актуализация 04.08 D39.99/D39.101; правки — только через оркестратора) @@ -333,7 +333,7 @@ | 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`) и печатает число в отчёт качества (`pipeline/quality.go:126`=`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 | | 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:218`=`ПИК с 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`-ом): **365 строк оплачены ПОДСТАНОВКОЙ цены, из них 344 боевые и 21 тестовая фикстура** (`m-req`→`m-act` 13, `fake-model` 8 — их надо вычитать, иначе $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:61`=`func (p *Pricer) PriceForResponse`) пробует `actual`, потом `requested`, потом якорь, и ни одно из ТРЁХ мест вызова не различает, какая ветвь сработала. Комментарий там же охраняет РОВНО ОДНО направление («премиальный ответ не должен биться по дешёвому дефолту»); обратное — когда провайдер маршрутизирует ВНИЗ — не охраняет никто: запрошен `pro`, ответила модель дешевле, счёт идёт по пину `pro`, $3.96 за 1M выходных против $1.20 вендорских у flash = **×3.3 из кармана читателя, молча**. ⇒ лечение двухчастное: завести слаг, который провайдер РЕАЛЬНО возвращает, и сделать срабатывание подстановки ВИДИМЫМ. Носитель работы — пак «падение, которое видно» §4.5 | бэкенд+полигон | **скоро** | вендор-сверка identity слага, затем пере-пин с датой и способом в формулировке; отдельно — наблюдаемость подстановки | критик чисел прогона A, 11.09; подстановка — пере-замер оркестратора 11.09 | +| 413 | ⛔⛔ **ЧИТАТЕЛЬ ПЛАТИТ ПО НАШЕМУ ПИНУ, А ПИН FLASH ПРОТУХ НА 13 % — и рядом НЕ РАЗРЕШЁННЫЙ вопрос, та ли это вообще модель.** Замерено полигоном на живом платном прогоне 11.09 и пере-проверено вендор-докой дважды (`api-docs.deepseek.com/quick_start/pricing`, гардрейл «идём в официальную доку, не гадаем»): наш пин `backend/configs/models.yaml:218`=`ПИК с 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:61`=`func (p *Pricer) PriceForResponse`) пробует `actual`, потом `requested`, потом якорь, и ни одно из ТРЁХ мест вызова не различает, какая ветвь сработала. Комментарий там же охраняет РОВНО ОДНО направление («премиальный ответ не должен биться по дешёвому дефолту»); обратное — когда провайдер маршрутизирует ВНИЗ — не охраняет никто: запрошен `pro`, ответила модель дешевле, счёт идёт по пину `pro`, $3.96 за 1M выходных против $1.20 вендорских у flash = **×3.3 из кармана читателя, молча**. ⇒ лечение двухчастное: завести слаг, который провайдер РЕАЛЬНО возвращает, и сделать срабатывание подстановки ВИДИМЫМ. Носитель работы — пак «падение, которое видно» §4.5 | бэкенд+полигон | **скоро** | вендор-сверка identity слага, затем пере-пин с датой и способом в формулировке; отдельно — наблюдаемость подстановки | критик чисел прогона A, 11.09; подстановка — пере-замер оркестратора 11.09 | | 414 | **ПРИЗНАК ОТКАЗА НЕ ЖИВЁТ В `err`: прогон, где четверть денег купила пустоту, читается через эту колонку как идеально чистый.** Замер 11.09 на живом прогоне: `err` пуст на ВСЕХ 33 строках `request_log`, включая четыре провальные (контроль: строк с `err <> ''` — 0). ⚠ **ИСПР. 11.09 — «единственный носитель» НЕВЕРНО, их ТРИ, и они сходятся точно.** Пере-снято мною по базе прогона (`bk_ROEHZBD46ALFI43E/project.db`, 33 строки): `ok = 0` ровно на четырёх провальных и `1` на остальных 29 · `finish_reason = 'length'` на тех же четырёх · `degraded` (`empty` ×3, `length` ×1). Каждый из трёх, просуммированный по деньгам, даёт **ровно $0.106472** — то есть провал виден тремя независимыми колонками, и `ok` из них самая очевидная. Верна ровно половина прежнего утверждения: пуст именно `err`. ⇒ любой аудит денег или отказов, написанный через `err` — а это первое, к чему потянется рука, — не увидит 25.4 % траты. Родня ряда **376**: там оплаченный обрыв не виден в оценочной паре, здесь провал не виден в колонке ошибок | бэкенд | скоро | отказ обязан быть видим тем же прибором, которым смотрят деньги | критик чисел прогона A, 11.09 | | 415 | ⛔ **ЧЕТВЕРТЬ ДЕНЕГ КНИГИ КУПИЛА ПУСТОТУ, И ПОДНЯТЫЙ ФЛОР ЭТОГО НЕ СНЯЛ — доля БОЛЬШЕ, чем у инцидента, ради которого флор поднимали.** Замер 11.09: 4 вызова из 27 вернулись без пригодного текста и стоили **$0.106472 = 25.4 %** книги; три из них вернули РОВНО 0 знаков ($0.094835 = 22.6 %), четвёртый — выброшенный обрезок. Самый дорогой одиночный вызов прогона ($0.071009, `edit`/`deepseek-v4-pro`) не дал НИЧЕГО. ⚠ Мина задокументирована (размышление съедает `max_tokens`), боевой `pipeline-c1.yaml` ставит на draft `reasoning: "low"` именно против неё — **сработала всё равно: трижды на draft и один раз на edit, где ручка не выставлена вовсе**; а `min_max_tokens: 16000` у `pro` поднят с 8000 ПОСЛЕ прошлого такого инцидента, чья цена записана рядом в комментарии как 15.5 % счёта — здесь один вызов НА ПОДНЯТОМ флоре сжёг 16 000 токенов и вернул ноль, **16.9 % счёта**. ⭐ Лечение в движке ЕСТЬ и сработало 4 раза из 4 (перевыпуск с удвоенным потолком вернул текст) — путь не рвётся, он ДОРОЖАЕТ вдвое. Вторая точка того же явления: на прогоне 08.09 было 32 % | бэкенд | **скоро** | ручка против мины на ВСЕХ платных стадиях + решение, платит ли читатель за выброшенную попытку | критик чисел прогона A, 11.09 | | 416 | **СОГЛАСИЕ НА ПЕРЕ-ОПЛАТУ, ВЫСТАВЛЕННОЕ НА ВЕСЬ БЮДЖЕТ, ПРИ ФАКТИЧЕСКОЙ ПЕРЕ-ПОКУПКЕ В 78 РАЗ МЕНЬШЕ.** Замер 11.09: на резюме после банк-стопа `runs.accept_rebill_micro = 2 241 631` — то есть согласие пере-оплатить ВЕСЬ бюджет прогона, — тогда как фактически пере-куплено $0.028742. Разрыв **78×**; от пере-покупки спасли чекпойнты, а не потолок согласия. ⇒ промахнись хэши промптов (смена провода, `memory_version`, снапшота), и черновая волна была бы куплена заново — с уже стоящим согласием читателя. Родня `D39.196` п.2а (переплата читателя запрещена): здесь запрет не нарушен, но и не охраняем ничем, кроме везения | платформа+бэкенд | скоро | согласие соразмерное тому, что реально может быть пере-куплено | критик чисел прогона A, 11.09 | @@ -341,10 +341,11 @@ | 419 | ⛔⛔ **СТЕММЕР СНИМАЕТ ОДНО ОКОНЧАНИЕ, И ИЗ 18 ПРОМАХОВ ЖИВОГО ПЛАТНОГО ПРОГОНА **11 — ЛОЖНЫЕ**: банковская форма ДОЕХАЛА до читателя в том же юните, склонённая, а пост-проверка её не увидела.** Замерено бэкенд-сессией по-юнитно на копии базы прогона A 11.09 (контроль: 84 показано − 66 последовало = 18, столько же записей в `postcheck_detail`). Механизм один: `TargetStemmer.Stem` снимает РОВНО ОДНО окончание, а двум падежным формам нужны окончания РАЗНОЙ длины ⇒ стеммы выходят разной длины, `SameStem` требует равенства (`backend/internal/lang/stemmer.go:70`=`func (s TargetStemmer) SameStem`), и во всех одиннадцати один стемм — строгий ПРЕФИКС другого с разницей в ОДИН знак («путь»/«пут» · «ветвь»/«ветв» · «крепость»/«крепост» · «злой»/«злог»). Примеры ложных: `正道` «праведный путь» → в тексте «школы праведного пути»; `白家寨` «крепость рода Бай» → «крепости рода Бай» ×2. **Настоящих расхождений 7**, и `家老`/`舅父` из ручного оракула прогона среди них. ⭐ **КЛАСС БЫЛ ПРЕДСКАЗАН, И ЛЕЧЕНИЕ НАЗВАНО В САМОМ ДЕРЕВЕ:** пять из одиннадцати — мягкий знак, исключённый из `decl_suffix` НАМЕРЕННО (`backend/internal/lang/data/target-ru.txt:231`=`the bare SOFT SIGN`, `D39.71`: иначе «Синь»/«Линь» схлопнутся на стеммы «синий»/«линия»), и записка там же говорит — «the soft-sign nominative gap needs seed decl-form enumeration or an **anchor-gated match**, not this global suffix». Пинг стоял; **цена его не была замерена до сегодня**. ⛔ Следствия: (1) число «18 расхождений» завышено в 2.5 раза — эррата 11.09-б; ⚠ **адрес испр. 11.09: числа 18 в теле `D39.247` НЕТ, оно жило в промте пака и в таблице `docs/README.md`, и там же исправлено;** (2) прибор консистентности, переиспользующий банковское равенство, НАСЛЕДУЕТ дыру и врёт примерно в 60 % строк — поэтому пак печатает ДВА числа (по равенству и по якорному послаблению), а разница есть цена стеммера; (3) точность глоссарного чекера **0.067** (ряд 408) — вероятно ТОТ ЖЕ механизм, а не данные сида; проверяется по `fp_ids` ⚠ **11.09: корень шире — ряд 423.** Ненулевые `decl.forms` есть только в рукописных сидах, в машинных выгрузках их НОЛЬ, поэтому на нормальной дорожке продукта одношаговый стеммер — единственное, что работает. | бэкенд | **скоро** | якорное послабление на БОЕВОМ пути `dstFormPresent` — отдельным паком, после замера прибором на размеченном корпусе | пак консистентности, 11.09 | | 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` найдено **448**, несут таблицу `request_log` **405**, прочитано **58 886** строк; ноль устоял на БОЛЬШЕМ знаменателе. Колонка объявлена схемой (`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 | +| 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 (контроль: прибор распарсил **47** yaml-файлов с непустым `terms:`): ненулевые `decl.forms` есть ТОЛЬКО в файлах, написанных человеком — `guzhenren-seed-v2.yaml` 42 терма из 58 · `guzhenren-seed.yaml` 35 из 49 · `rerun2` 41 из 57; **во ВСЕХ машинных выгрузках — ноль**: 0 из 142 · 0 из 102 (шесть раз) · 0 из 83 · 0 из 76 · 0 из 74 · 0 из 69 (банк платного прогона A) · 0 из 67 · 0 из 61 · 0 из 53. ⇒ **на книге без рукописного сида — то есть на нормальной дорожке продукта — пост-проверке нечем опереться, кроме глобального одношагового стеммера**, и это ровно тот механизм, который ряд **419** замерил как дающий 11 ложных тревог из 18. Три инстанса одного класса: `decl.forms` (`internal/seed/seed.go:87`=`type Decl struct`, потребитель `membank/memory.go:343`=`Parse decl forms for the post-check`) · профили голоса (ряд **410**: `voices:` пуст во ВСЕХ 22 машинных выгрузках и отсутствует во ВСЕХ 22 рукописных сидах) · формы глагольных и многословных термов (ряд **408**). ⭐ **Ценность ряда в том, что он снимает три отдельные «доработки данных» и ставит один вопрос: что банк обязан отдавать, кроме пары «исходник → передача», чтобы механизмы ниже работали не вырожденно.** ⚠ Это НЕ заказ «научить майнер всему»: часть полей модель предложить не может в принципе (склонение — да, голос — спорно), и разделение «что майнится · что сеется человеком · что вычисляется из языка» и есть предмет. ⛔ Пока ряд открыт, любой замер точности пост-проверки на РУКОПИСНОМ корпусе меряет исключение, а не правило — этим 11.09 ошибся оркестратор, решая порядок колонок прибора консистентности | бэкенд | **скоро** | разделение «майнится · сеется · выводится из языка» + носитель того, чего майнер не даёт | пере-замер оркестратора 11.09 по числу зоны `textmachine-c9` | -| 424 | **ЧЕТЫРНАДЦАТЬ РЯДОВ ТРЕКЕРА РЕНДЕРЯТСЯ С ЛИШНИМИ КОЛОНКАМИ — неэкранированный `\|` внутри ячейки, обычно в код-спане вида `auto\|draft\|approved`.** Замер 11.09 структурной проверкой по всей таблице (контроль: рядов прочитано **298**, сломанных **14**): 163 · 182 · 248 · 127 · 253 · 279 · 306 · 311 · 320 · 346 · 361 · 378 · 389 · 407. Лечение — `\|` в ячейке; работа механическая. ⭐ **Ряд заведён не ради косметики, а потому что гейт этого НЕ ВИДЕЛ, и слепота стоила инцидента:** проверка формы в `docs/scripts/counts.py` ловила только «колонок МЕНЬШЕ ожидаемого», а «больше» и «текст за последним разделителем» молчали — и ряд **406** прожил от создания до 11.09 с **1044 знаками текста ВНЕ таблицы**, при этом счётчики сходились (они читают ячейки с конца и попадали в нужные) и гейт был зелён. Проверка сделана симметричной тем же днём, эти 14 внесены в `SHAPE_GRANDFATHERED` по конвенции файла «гейт рождается зелёным на известном долге и краснеет на следующем»; три посадки на копии подтвердили, что обе новые половины краснеют ПО ТЕКСТУ, а дедовщина молчит. ⇒ закрытие ряда = экранировать 14 ячеек и вынести их из списка | оркестратор | когда-нибудь | экранирование `\|` в четырнадцати ячейках и пустой `SHAPE_GRANDFATHERED` | структурная проверка оркестратора 11.09 | +| 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 добавил одиннадцатый счёт того же прогона в другой момент времени. ⇒ **любой денежный свод, собранный обходом файлов по диску, завышает трату кратно числу копий**, и это первое, к чему потянется рука при вопросе «сколько мы потратили за день». ⚠ Родня трёх ловушек акта `D39.247` п.5 (`run_attempts.spend_micro_usd` накопленная · `err` пуст на провалах · `chunk_status` недобирает терминологию) — у всех один класс: **прибор денег отвечает на вопрос, которого ему не задавали.** Лечение — не код, а норма свода: деньги считаются по УНИКАЛЬНОМУ `(book_id, date)` либо по одной авторитетной базе, и рядом печатается, сколько файлов прибор обошёл | оркестратор | скоро | норма денежного свода в ролевом промте + дедупликация по `(book_id, date)` | приёмка пака консистентности, 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 | diff --git a/docs/scripts/counts.py b/docs/scripts/counts.py index 0fc5c2e6..4437d6a4 100644 --- a/docs/scripts/counts.py +++ b/docs/scripts/counts.py @@ -172,7 +172,9 @@ def weight_of(line: str) -> str: # Ряды, у которых лишние колонки — ЗНАЕМЫЙ долг: неэкранированный `|` внутри ячейки (обычно в # код-спане вида `auto|draft|approved`). Та же конвенция, что у WEIGHT_GRANDFATHERED: гейт рождается # зелёным на известном и краснеет на следующем. Долг числится строкой бэклога 424. -SHAPE_GRANDFATHERED = {"163", "182", "248", "127", "253", "279", "306", "311", +# ⚠ 253 СНЯТ 11.09: он в этот список попал по ошибке — я считал разделители наивно, а этот ряд их +# ЭКРАНИРУЕТ, и расщепитель гейта видел его целым. Дедовщина на неcломанном ряде слепит гейт там навсегда. +SHAPE_GRANDFATHERED = {"163", "182", "248", "127", "279", "306", "311", "320", "346", "361", "378", "389", "407"}