diff --git a/docs/BACKEND_ENGLISH_PAIR_SESSION_PROMPT.md b/docs/BACKEND_ENGLISH_PAIR_SESSION_PROMPT.md new file mode 100644 index 00000000..65b7d0d7 --- /dev/null +++ b/docs/BACKEND_ENGLISH_PAIR_SESSION_PROMPT.md @@ -0,0 +1,427 @@ +# Бэкенд-пак: АНГЛИЙСКАЯ ПАРА en→ru — движок обязан ЗАПУСТИТЬСЯ и отдать книгу, которую можно читать + +> Выдача №15 очереди №23. Зона — `backend/`. Пак **$0 по умолчанию**; единственный платный шаг назван в +> §4.10 и без моего слова не делается. +> ⚠ **Числа и адреса этого промта сняты МНОЙ по дереву 17.09, каждое — названным прибором.** Те, на +> которых ты строишь решение, пере-сними своим: заимствованное число улики не заменяет. +> ⛔ **И честно о цене этого правила: первая редакция промта содержала ЧЕТЫРЕ моих ошибки**, все нашёл +> опровергатель, и все — одного класса: **число снято не на той популяции**. Я мерил текст документа там, +> где движок читает ГРУППУ документов; цитировал отозванную формулировку ряда, не прочитав его баннер; +> обрезал строку ноты на 200 знаках и заключил, что тела нет. Ниже — исправленное. Считай это не +> извинением, а описанием того, как именно здесь ошибаются. + +## 1. Какая проблема и что решит твой результат + +Проект объявляет: движок один, пара — ДАННЫЕ, и ревью-вопрос по умолчанию — «заработает ли пара, которой +в репо ещё нет, без правки Go?». На английском ответ сегодня — **нет, и даже не «плохо», а «не стартует»**. + +Замерено мной: + +- `backend/configs/pairs/en-ru.yaml` — **293 байта, 6 строк**: только `pair: en-ru` и коридор + `len_ratio_bounds: [0.70, 1.4]`. ⭐ Его собственный комментарий уже называет обе стены: «своей калибровки + нарезки нет, пакета промптов `prompts/en-ru/` нет (книга на этой паре упадёт громко на загрузке)». + **Это не открытие пака — это пин в данных, написанный раньше нас.** +- `backend/prompts/` — **один** пакет (`zh-ru`, 11 файлов). `backend/configs/langpacks/` — **три** + (`ru`, `zh`, `zh-ru`). +- Целевой слой (русский) привязан к **ЦЕЛИ**, а не к источнику ⇒ английская пара наследует слой 7, + банк-инъекцию и читательские слова **бесплатно**. Работа лежит на осях ИСТОЧНИК и ПАРА. + +**Твой результат:** английская книга проходит от интейка до файла, который читает человек, а деньги, эхо и +нарезка ведут себя на латинице так же честно, как на китайском. + +⚠ **Три решения владельца (17.09) — исполняются, не обсуждаются:** книга — **«Империя рассвета»** +(Кристофф, том 3 «Империи вампиров», `books/Kristoff_Jay_-_Empire_of_the_Vampire_3_-_Empire_of_the_Dawn.epub`, +18 634 457 байт, в дереве); размер среза меряется **по токенам** — равной работой и деньгами; **эксперимент +двух переводов идёт ПОСЛЕ этого пака**, обе половины сразу. + +## 2. Зона записи и git + +Пишешь `backend/` и свою секцию в `docs/PROGRESS.md`. **Не коммитишь** — дерево передаёшь мне. Чужие +незакоммиченные файлы не трогаешь. **`.env` не читаешь никогда.** Запрещены `git add -A` / `git add .` / +`git commit -a`, `reset --hard`, переписывание истории, `checkout` поверх грязного дерева. Книги и +производные не коммитятся: `books/` — симлинк в отдельный репозиторий со своим origin. + +⚠ **`books/` невидим двум приборам сразу, и оба дают ложный ноль:** обёртка `grep` чтит `.gitignore`, а +`find` не спускается в симлинк без `-L`. Замер: `find books -type f` → **0**, `find -L books -type f` → +**10534**. Бери `command grep` и `find -L`, и печатай знаменатель рядом с любым нулём. + +⛔ **ВХОД ЗОНЫ.** Дерево передаётся тебе ПОСЛЕ лендинга предыдущего пака (`backend/` сейчас держит 31 +незакоммиченный путь чужой банк-работы). Твоя первая команда — `make battery` на полученном дереве, и её +результат ты **записываешь числом в записку-план как ВХОДНУЮ строку**. Красное на входе — пинг мне, а не +починка: это не твой предмет. + +## 3. Карта чтения — ЗАКОН, пять позиций + +1. `CLAUDE.md` (корень) — канон, гардрейлы, роли зон. +2. `docs/architecture/09-target-architecture.md` §0.1 и §Цели — почему пара это ДАННЫЕ. +3. `docs/architecture/12-go-style-notes.md` §1 — норматив зоны. +4. `docs/experiments/00-provider-quirks.md` — провайдерские ловушки, ПЕРЕД правкой вызовов. +5. `docs/experiments/01-token-calibration.md` — калибровка: английский **3.64** знака без пробелов на + токен, китайский **1.38**. + +**Код первичен:** адреса ниже — отправные точки, не истина. + +## 4. Что построить + +### 4.1. ОСТАНОВКА ПЕРВАЯ — до единой строки кода. ДЕЛАЙ РОВНО ТАК + +**Слово владельца:** «обязательно остановись на селф ревью и выдай сессии… фабла5 который верифицирует +алгоритм исполнения и данных в бэкенде для английского + адверсариальное селф ревью и контроль исполнения». + +1. **Инвентарь исполнением.** Пройди путь английской книги СВОИМИ прогонами и выпиши, где он встаёт. + Отправные точки (все четыре проверены мной по содержимому цели): + `backend/internal/config/pipeline.go:1063` · `backend/internal/pipeline/runner.go:364` · + `backend/internal/lang/structure.go:158-161` · `backend/internal/pipeline/runner.go:432-439`. +2. **Прочитай, что УЖЕ померено живьём на этой самой книге** — ряд **315** бэклога закрыт замером 06.09: + `tmctl manifest`, `EXIT 0`, $0, `structure: declared`, **71 глава / 351 юнит / 356 чанков**, нумерация + плотная 1..71, `title_raw` на проводе 71 из 71, `heading` пуст у ВСЕХ глав. ⛔ Не открывай это заново. +3. **Подними советчика Fable 5 — ОДНОГО, с постоянным контекстом** (`model: "fable"` явно; канон: один + фабл на сессию, вопросы ДОСЫЛАЮТСЯ тому же агенту, второго не поднимают). Предмет задай: «вот алгоритм + исполнения английской пары и данные, которые я заведу; найди, где он ломается на латинице и где данные + не выражают того, что обещают». Он **советчик, а не источник истины** — посылки проверяются деревом. + ⚠ Обычные субагенты потолком не ограничены; их поднимать разрешаю явно. +4. **Только после этого** — записка-план (§7) и первая строка кода. + +### 4.2. Стена 1 — промт-пакет пары. Это СОДЕРЖАНИЕ, и оно главное. РЕШИ САМА состав + +Загрузчик ищет промт по конвенции `/<пара>/<роль>.md` +(`backend/internal/config/pipeline.go:545`); файла нет — `RefusalBadConfig`, `EXIT 10`. + +⚠ **Стена НЕ абсолютна, и это уже использовано:** у пар-конфига есть ручка `prompts_root` +(`backend/internal/config/pair.go:33`), и именно ею предыдущий пак прогнал ЭТУ книгу без каталога +`prompts/en-ru/` в дереве (ряд 315). ⇒ **пакет строится не для того, чтобы обойти стену, а потому что он +ПРОДУКТ** — прямой рычаг против translationese, цель №1 канона. + +⛔⛔ **И ВОТ ГЛАВНОЕ В ЭТОМ ПАКЕ — СЛОВО ВЛАДЕЛЬЦА 17.09, ДОСЛОВНО:** «код может быть и да, но вот +**данные надо написать**. Посмотреть на китайский и по аналогии, но при этом **уникально описать +английский язык**. Это очень важно так как от этого **качество перевода зависит**. Именно поэтому я тебе и +разрешал выдать фабла 5 другой сессии которая этот пак будет исполнять». + +⇒ **Центр пака — не стены и не тихие дефекты, а СЛОЙ ДАННЫХ АНГЛИЙСКОГО ЯЗЫКА.** Китайский смотришь как +образец ФОРМЫ — какие вопросы язык обязан о себе ответить, — и отвечаешь на них **про английский, его +собственными категориями**. ⛔ Перенос китайских категорий на латиницу — это и есть та «копия без +предмета», которая зеленеет и портит перевод молча. + +**Образец в числах (замер мой, непустые строки).** `configs/langpacks/zh/` — одиннадцать обязательных +таблиц канала морфологии, и вот их наполнение: `title-suffix` 26 · `ordinal-title` 15 · +`surnames-compound` 15 · `rank-word` 8, а `alias-particle` · `grade-prefix` · `numeral` · +`sentence-terminator` · `surnames-single` · `title-formant` · `topo-suffix` — по **одной**. +`configs/langpacks/zh-ru/` — четыре файла пары: `palladius` 87 · `dc-checkers` 42 · +`palladius-phonotactics` 16 · `heading` 1. `configs/langpacks/ru/reader.txt` — 7 строк, и **его английская +пара наследует даром**: целевой слой привязан к цели. + +⭐ **Отсюда свобода, которую надо знать до начала:** загрузчик требует, чтобы объявленная таблица была +**НЕПУСТОЙ**, а не полной (`backend/internal/lang/langpack.go:519-529`, каждая строка — `req(...)`). Семь +китайских таблиц из одиннадцати удовлетворяют это одной строкой. ⇒ **английский вправе описать себя +по-своему и коротко там, где ему нечего сказать, — но НЕ вправе соврать**, положив туда китайское. + +**Что английский обязан рассказать о себе, и чего в китайском нет вовсе** (это направление, а не список — +состав решаешь ты и защищаешь аргументом): + +- **Регистр как сигнал имени.** В китайском регистра нет; в английском заглавная буква — главный носитель + «это имя собственное», и нормализация ключа его СТИРАЕТ (§4.7). Что тогда несёт сигнал? +- **Частицы и приставки фамилий** — `de` · `van` · `von` · `O'` · `Mc` · `Mac` · `Fitz`: где кончается + частица и начинается имя, и как это едет в русский. +- **Титулы и звания** — их у английского два слоя: препозитивные (`Sir`, `Lord`, `Captain`) и + постпозитивные (`Jr.`, `Sr.`, `PhD`), и китайская таблица `title-suffix` описывает только второй род. +- **Дефисные и многословные имена собственные**, которых китайская односложная морфология не знает. +- **Топонимические форманты** — `-ton`, `-shire`, `-ville`, `-burg`: аналог `topo-suffix`, но с другой + механикой границы слова. +- **Числительные словами** — `One`, `Twelve`, `Thirty-first`: в китайском это иероглифы-цифры, в + английском слова, и именно на этом ломается разрез глав (§4.4). +- **Терминаторы предложения и сокращения**, где точка не кончает предложение (`Mr.`, `St.`, `vs.`) — + ⚠ секция `en` в `backend/internal/lang/data/sentence-abbrev.txt` уже существует и её НЕ дублируй. + +⛔ **ТРАНСЛИТЕРАЦИЯ — ОТДЕЛЬНЫЙ ВОПРОС, И ОТВЕТИТЬ НА НЕГО НАДО ЯВНО.** Канал транслитерации требует +поимённо пиньинь-категории (`backend/internal/lang/langpack.go:531-540`): `palladius/initials` · `finals` · +`yw` · `special_i` плюс три фонотактических. Английская практическая транскрипция — **другая система**, и +в этой схеме она невыразима. Штатный механизм для источника, который НЕ везёт этот канал, в движке есть: +`manifest.txt` объявляет, какие каналы источник ШЛЁТ (`backend/internal/lang/langpack.go:612`), и +`D39.64` (строка реестра `docs/architecture/05-decisions-index.md`, пункт П4) ратифицировала ровно это +намерение — источник без пиньинь-морфологии грузится без палладиевых файлов. + +⭐ **Механизм подтверждён МОИМ чтением по пяти точкам, а не предположен** (`backend/internal/lang/langpack.go`): +манифест отсутствует ⇒ включаются ВСЕ каналы (`:624`=`no manifest → every channel`); пустое объявление +падает громко (`:644`=`manifest declares no channel`); файлы пары читаются ТОЛЬКО под гейтом канала +(`:280`=`if channels[channelTransliteration]`); требование пиньинь-категорий стоит под тем же гейтом +(`:531`=`if p.channels[channelTransliteration]`); свёртка хеша оверлея отсутствующий файл ТЕРПИТ +(`:410`=`if !ok {` → `return nil`). ⇒ **`en/manifest.txt` с единственной строкой `channelsource-morphology` +снимает пиньинь целиком, без единой строки Go.** + +**ДЕЛАЙ РОВНО ТАК: проверь этот путь СКВОЗНЫМ прогоном первым делом** — моё чтение говорит, что он +работает; твой прогон говорит, что он работает НА САМОМ ДЕЛЕ, и это разные утверждения. +⚠ Разойдётся — это находка, пинг мне, и заказ меняется. +⚠ И назови в отчёте цену выбранного пути: без канала транслитерации передача английских имён в русский +держится промтом и сидом, а не движком. + +**Советчик Fable 5 (§4.1) поднимается ИМЕННО ПОД ЭТО.** Слово владельца связывает его с данными прямо: +он верифицирует «алгоритм исполнения И ДАННЫХ в бэкенде для английского». Спрашивай его не «хорош ли +файл», а **«что английский язык обязан о себе сказать, чтобы перевод не стал translationese, и чего в +моём описании не хватает»**. Его посылки проверяй деревом. + +Состав живой пары `zh-ru` — 11 файлов: `translator.md` · `editor.md` · `editor-mono.md` · +`terminologist.md` · `classifier.md` · `translator-banknote.md` · `judge-selector.md` и `repair/` с +четырьмя (`broken_word` · `dc1_fractional` · `dc1_time_units` · `latin_residue`). + +**РЕШИ САМА, с аргументом**, какие нужны английской паре. Мой приор, опровергаемый твоим замером: +`dc1_fractional` и `dc1_time_units` — про китайские числительные и часы, предмета у латиницы нет. +**Не копируй файл, у которого нет предмета: копия без предмета — вид лжи, которая зеленеет.** + +⛔ **НО У ЭТОГО СОВЕТА ЕСТЬ УСЛОВИЕ, И БЕЗ НЕГО ОН ОПАСЕН.** `loadRepairTemplates` +(`backend/internal/pipeline/repair.go:151`) возвращает `nil` сразу при выключенном гейте (`:152-154`), а +при ВКЛЮЧЁННОМ отсутствие файла класса — **громкий отказ с именем пути** (`:170-172`). Дефолтный набор +актуаторов — ровно два класса, и первый из них `RepairLatinResidue` (`:117-120`). Сегодня совет безопасен, +потому что `gates.repair` не включён нигде: **0 из 5** файлов `backend/configs/*.yaml`; единственное +упоминание в 26 конвейерах книг — комментарий, прямо говорящий «repair выключен». ⇒ **условие названо: +совет держится, пока гейт выключен; включишь — отсутствие файла станет падением.** + +Пиши промты как переводчик, а не как инженер: английский источник несёт то, чего нет в китайском — артикли, +время глагола как носитель сюжета, атрибуцию прямой речи внутри абзаца. Русские целевые данные НЕ трогаешь. + +### 4.3. Стена 2 — гейт терминолога. ДЕЛАЙ РОВНО ТАК: сперва путь данными + +`backend/internal/pipeline/runner.go:364`: при `forWrite && Gates.Terminology.Enabled && r.pack == nil` — +отказ. Замер со знаменателем: гейт включён в **трёх** конфигах из четырёх (`backend/configs/pipeline-c1.yaml:150`, +`backend/configs/pipeline-arm-glm.yaml:60`, `backend/configs/pipeline-arm-mistral.yaml:67`); у `pipeline-c2.yaml` секции нет, но ⚠ это +**не обходной путь**: `c2` — скелет ДРУГОГО ядра (generate-then-select), неисполнимый раннером фазы 0. + +⭐ **Путь данными существует.** Гейты живут в ПАЙПЛАЙН-файле, который книга называет полем `pipeline:` +(`backend/internal/config/book.go:79`). Замер: **все 23** `book.yaml` объявляют конвейер, из них **19** +называют `pipeline.yaml` и **4** — не-дефолтное имя. ⇒ конвейер английской книги с выключенным +`gates.terminology` снимает отказ **без единой строки Go**. + +**Правку Go под ряд 347 НЕ делай без моего слова:** ряд **35** предупреждает, что снятие отказа без +не-Han детектора «обещает больше, чем покупает» — банка на латинице всё равно не будет. + +⚠ **Назови цену пути данными в отчёте:** без добытого банка нет сквозной консистентности терминов, то есть +частично теряется цель №1. Вторую цену движок называет сам (`backend/internal/pipeline/runner.go:380`): канал банкноты при пустом +паке **платит за выход, который никто не прочтёт** — гаси `gates.banknote` тем же конфигом. + +### 4.4. Нарезка глав — предмет ПЕРЕ-ОПРЕДЕЛЁН. РЕШИ САМА форму, но популяцию бери движковую + +⛔⛔ **ЧИТАЙ ЭТО КАК ПРЕДУПРЕЖДЕНИЕ О МЕТОДЕ.** Первая редакция промта утверждала «71 глава, из них 67 +ПУСТЫ». Это было **ложно**, и ложно ровно потому, что число снято не на той популяции: я померил текст +документа-цели `navPoint`, а движок читает **ГРУППУ**. `groupChapters` +(`backend/internal/chunk/epubtoc.go:293-321`) в ветке `default` делает `last.docs = append(last.docs, i)` — +каждый читаемый не-граничный документ приписывается к ПРЕДЫДУЩЕЙ главе; рядом стоит инвариант сохранения +(`backend/internal/chunk/ingest.go:836-843`), а комментарий чтения гласит «Reading happens per GROUP so a +chapter split across documents arrives whole». + +**Популяция движка, пере-снята мной его же правилом (python-реимплементация `resolveTOC`+`groupChapters`):** + +| | | +|---|---| +| глав | **71** · приписано документов **53** · **ПУСТЫХ 0** | +| сумма прозы | **1 313 224** знака без пробелов ≈ 360 775 токенов — вся книга | +| крупных глав | **6**: BOOK TWO 321 191 · BOOK ONE 283 459 · BOOK FIVE 227 308 · BOOK FOUR 213 052 · BOOK THREE 148 922 · BOOK SIX 115 310 | +| крошечных (<200 знаков) | **65** | + +⭐ **Следствие для меры владельца: срез СУЩЕСТВУЕТ УЖЕ СЕГОДНЯ.** Цель — 41 027 токенов (20 китайских +глав). **BOOK THREE = 148 922 знака ≈ 40 912 токенов, промах −0.3 %.** Одна глава движка, без единой +правки. ⇒ **нарезка НЕ блокирует эксперимент**, и заказывать её как блокер было бы ложью. + +**Настоящий дефект другой и он о КАЧЕСТВЕ:** шесть «глав» по 115–321 тыс. знаков — это не главы, а части +книги, и 65 границ стоят на страницах-разделителях. Читатель получит шесть полотен вместо семидесяти одной +главы. Это предмет ряда **283**. + +**РЕШИ САМА**, чинить ли это в паке; если чинишь — порог «сколько знаков делает главу главой» живёт в +ДАННЫХ, а не в Go, и правило проверяется на ВТОРОЙ живой английской книге: `books/fifty_shades_1_en.epub` +и `books/fifty_shades_1_en.txt` (909 093 байта; строк вида `Chapter …` в начале строки — **26**, разрывов +страницы — **0**; оба числа мои, команда `command grep -cE '^[[:space:]]*Chapter '`). + +⚠ **Соседний предмет, ТВОЙ вход, а не открытие по ходу — ряд 303:** не-CJK **TXT** режется в одну главу +(лестница отдаёт `nil`, фолбэк — разрыв страницы, которых в живом английском txt ноль). Наша книга — EPUB, +её это не задевает. **Назови границу явно**, иначе следующая смена прочтёт пак как «не-CJK нарезка +починена». + +### 4.5. Порог эха — ДЕНЬГИ. ДЕЛАЙ РОВНО ТАК: сперва замер, потом число + +`backend/internal/pipeline/disposition.go:465`: `const cjkEchoThreshold = 0.15`, применяется на `:403` к +доле рун ИСХОДНОГО скрипта в выходе; доля считается от ВСЕХ рун, включая пробелы (`:472-484`). Конфиг-ручки +нет. + +Для en→ru исходный скрипт — **латиница** (`backend/internal/lang/data/lang-script.txt`: `en latin`), а +здоровый русский перевод английской книги несёт латиницу штатно. ⇒ 15 % достижимы без эха, а **ложный флаг +ЭСКАЛИРУЕТ**, то есть покупает платный хоп за здоровый текст. + +⛔ **ЧИСЛО 0.15 СНЯТО НЕ В ЭТОЙ КЛЕТКЕ** — оно унаследовано от китайского бенчмарка отказов. Измерь его на +латинице ТЕМ ЖЕ кодом, что и движок, и покажи распределение. Носитель предмета — ряд **260**. + +⛔ **Литерал порога ВХОДИТ в версию классификатора — пере-снято мной:** +`backend/internal/pipeline/disposition.go:186` несёт `classify-v3-refusal+srcscript-echo015+…`, то есть +подстроку `echo015`. ⇒ движение порога двигает ВЕРДИКТЫ и требует пере-снапшота. Порядок работ отсюда +следует жёстко: порог трогается в ТОМ ЖЕ окне, что и нарезка, либо не трогается вовсе. + +### 4.6. ⛔ ВТОРОЙ ДЕТЕКТОР ЛАТИНИЦЫ — его не было в первой редакции, и он противоречит §4.2 + +На каждом финальном чанке en→ru работает ВТОРОЙ счётчик латиницы, и он **не гейчен ничем, кроме цели**: +`lintLatinResidue` (`backend/internal/checks/checkers.go:561`, порог `minLatinResidueLen = 3` на `:559`) +вызывается из `RunCheapGates` (`backend/internal/checks/cheapgates.go:194`), а та бежит при +`r.checkers.TargetActive()` (`backend/internal/pipeline/waverun.go:626` и `:760`) — для цели `ru` всегда. + +⛔ **Его докблок (`backend/internal/checks/checkers.go:550-553`) утверждает ПРОТИВОПОЛОЖНОЕ тому, что §4.2 велит вписать +переводчику:** целое латинское слово в не-латинской цели — утечка, «в русской цели латинское имя +собственное **должно быть транслитерировано**», и правило объявлено **language-general** («Latin is not +pair data»). + +⭐ **Штатный механизм канон называет сам, и он НЕ порог:** «a legitimately-kept brand lives on the +per-project allowlist, not on a „has a capital“ heuristic». ⇒ законная латиница английской книги едет через +**аллоу-лист проекта**, а не через правку порога и не через промт переводчика. + +**ДЕЛАЙ РОВНО ТАК:** сперва замерь, сколько срабатываний даёт этот детектор на здоровом русском переводе +английской прозы; потом решай. ⚠ И помни условие §4.2: пока `gates.repair` выключен, детектор только +считает; включённый — становится актуатором с классом `latin_residue` в дефолте. + +### 4.7. Ключи банка на латинице — РЕШИ САМА, но сперва измерь + +`backend/internal/text/norm.go` завершает нормализацию ключа `unicode.ToLower`. Для китайского это no-op; +для английского — стирает признак, отличающий имя от обычного слова. Порог допуска не-Han ключа — 3 руны +(`backend/internal/membank/memory.go:78-83`), `collisionProneKey` ловит только ≤3 (`:88-90`), а демоушен +пост-чека Han-only (`backend/internal/membank/mempostcheck.go:151-156`) для английского не применяется +никогда. + +⚠ **Это подозрение, а не замер.** Первый шаг — измерить на нашем материале, сколько ключей фирят на +обычных словах, и только потом решать. + +### 4.8. Бюджет нарезки — РЕШИ САМА, и оценка законна вместо прогона + +`backend/internal/chunk/chunker.go:85-96`: `est_out = FertCJK·cjk + FertOther·other`; у английского плотных +рун ноль. Последний фолбэк — 1.1978 / 0.3852 с комментарием в самом файле: это **zh-ru пар-калибровка, а не +языко-нейтральная константа**. У `en-ru.yaml` блока `segmentation` нет. + +⚠ **Ряд 14 держит этот предмет с оговоркой «калибровка ждёт боевого токенизатора», и рядом в той же строке +предупреждает, что громкий segmentation-фолбэк ломает контракт коридора и голден-фикстуру на нём.** ⇒ +калибровочный ПРОГОН деньгами §4.10 не выдан. **Заведи блок по ОЦЕНКЕ, назови её оценкой** — либо скажи +«не делаю» с доводом. Правки Go это не требует. + +### 4.9. Что в пак НЕ входит + +- **Не-Han майнер банка** (ряд **35**): майнер Han-only по построению + (`backend/internal/miner/miner_substrate.go:44-63`), на латинице кандидатов ноль. Отдельный пак. +- **Правка Go под ряд 347** — без моего слова (§4.3). +- **Целевая латинописьменная пара (→en)** — ряд **259**. +- **Транслитерационный канал** под пиньинь: требование категорий — `backend/internal/lang/langpack.go:531-540` + (⚠ ряд 347 несёт устаревший адрес `:521-527`, который указывает в блок МОРФОЛОГИИ; ряд мой, пере-наведу я). +- **Японская пара.** Мой замер по ходу: CJK-дефолт не режет ни одну из двух живых японских книг — + ратифицирую отдельной нотой я, тебе не предмет. ⚠ Метод замера назову в ноте: движок сравнивает по + `strings.TrimSpace` (`backend/internal/chunk/chunker.go:210`), а не по началу строки. +- **`gates.repair` остаётся выключенным.** Включение — отдельное решение с ценой (§4.2, §4.6). + +### 4.10. Деньги — и здесь ДВА разных предмета, которые нельзя путать + +Пак **$0** до момента, когда пара собрана. Тогда — **одна дымовая покупка** на ОДНОЙ главе (не на срезе), +чтобы доказать, что путь доходит до файла. **Перед ней — пинг мне с ценой ДО траты:** оценка в токенах и +долларах, потолок в `book.yaml` самой книги. Полный срез принадлежит ЭКСПЕРИМЕНТУ, не паку. + +⛔ **Пере-снапшот — НЕ одно и то же на двух книгах, и первая редакция промта это смешивала.** +`--resnapshot` дословно: «re-pin existing jobs to the current config snapshot (**re-translates +already-paid chunks** — explicit consent)» (`backend/cmd/tmctl/invocation.go:131`), согласие — +`--accept-rebill` (`:133`). ⇒ на **английской** книге пере-снапшот **$0**: оплаченных прогонов там нет, +платить нечего. На **китайских стендовых** базах это ДЕНЬГИ и требует явного согласия — в пак они не +входят. Голден-файл в дереве **один** (`backend/internal/pipeline/testdata/golden/capture.golden`). + +⚠ Потолки банк-ролей **пожизненные**; на английской книге они тратиться не должны — если тратятся, это +находка. + +### 4.11. Стандарт работы + +Ценность продукта → архитектура → необходимый рефакторинг → без велосипедов. Сверка с индустриальным +первоисточником прежде собственного изобретения. Книжный термин в общем пар-слое — утечка. + +## 5. Самопроверка ИСПОЛНЕНИЕМ — и где у ЭТОГО пака мягко + +Мандат: **самопроверка исполнением, не перечитыванием.** Субагентов поднимать **разрешаю явно**. Тест на +вырожденность: пункт, удовлетворяемый фразой «перечитал сам», — дефектен. + +⛔ **Контроль исполнения — ПО ХОДУ, а не в конце** (слово владельца): раз в заметный кусок работы сверяй +сделанное с ПЕРЕЧНЕМ ЗАКАЗА этого промта — списком, не по памяти. + +⭐ **Прибор для этого, купленный приёмкой 17.09 (формулировка зоны):** собственные проверки не находят +ОТСУТСТВУЮЩЕЕ, потому что знаменателем им служит твой же текст. Спросить у дерева, сходится ли отчёт, ты +умеешь; спросить у отчёта, все ли предметы названы, — нет, список берётся оттуда же. ⇒ **сверяй перечень +заказа с перечнем отчёта по СПИСКУ ЗАКАЗЧИКА** — тем же движением, что `comm -23` над пакетами батареи. + +**Мутации — часть заказа, а не только критерия приёмки.** Каталог сегодня `backend/cmd/tmmutate/mutations.json` +(526 записей, 315 в гейте `battery`). Заведи записи на КАЖДУЮ новую ветку, которую пак создаёт (нарезка · +порог эха · аллоу-лист · путь данными вокруг гейта), пометь их `battery` и прогони каталог ЦЕЛИКОМ, а не +поодиночке. ⚠ Не сужай прогон через `-run`, чтобы влезть в память: подмножество не есть пакет. + +**Где у ЭТОГО пака мягко — пять мест; глубину и веер выбираешь ты:** + +1. **Промты пары — единственное, что не ловится ни одним гейтом.** Батарея зелена при любом их содержании. +2. **Порог эха**: соблазн подвинуть число, не измерив; ошибиться можно в обе стороны. +3. **Популяция**, на которой снято любое число о главах: документ ≠ группа. Здесь я уже ошибся — проверь + каждое своё число вопросом «на чём его читает ДВИЖОК». +4. **Детектор латиницы спрошен на ЦЕЛИ, а не на источнике** — гейт `TargetScriptNonLatin` отвечает про + русскую цель и от английского источника не защищает. +5. **Путь данными вокруг гейта терминолога** снимает ОТКАЗ, но не даёт банка. Легко отчитаться «английский + пошёл» и умолчать, что пошёл без механизма, ради которого гейт стоял. + +**Адверсариальный проход по СВОЕЙ готовой работе — обязателен**, отдельным заходом после объявления +готовности. Мандат: «найди, что этот пак сломал и о чём умолчал». + +## 6. Оси ревью — предметные, а не гигиенические + +1. **Число снято на документе, а не на группе** (и шире: на популяции, которой движок не пользуется). +2. **Детектор спрошен на цели там, где предмет — источник** (и наоборот). +3. **Промт пары проверен НАЛИЧИЕМ файла, а не текстом**, который он производит. + +## 7. Записка-план + +После §4.1 и до первой строки кода: что строишь, в каком порядке, чем предъявишь каждый пункт, плюс +ВХОДНАЯ строка батареи числом. Пишешь в свою секцию `docs/PROGRESS.md`. + +## 8. Заявление = команда + +Каждое число и каждая категорика отчёта — **с командой, которой получены**. Приёмка пере-ранит своим +прибором; число без команды принимается «со слов» и так называется в акте. + +## 9. Эхо-протокол старта + +До работы — **≤10 строк СВОИМИ словами**: скоуп · инварианты · что НЕ делаешь. ⚠ Дословный пересказ +подтверждает канал, но не понимание, и повторяет ошибку промта вместе с ним. + +## 10. Что не удалось и где прибор слеп — обязательная секция + +Две половины: **«что не получилось»** и **«что ты знаешь и не сказала»** — в форме «что невидимо · почему +не чинила · чем закрывается». ⭐ **В коде названо, в отчёте нет — значит для следующей смены НЕ названо.** + +## 11. Канал вопросов, право отказа, советчик + +Конфликт промта с кодом или доками — **пинг, а не интерпретация**. У тебя есть **право сказать «этого +делать не надо»** с аргументом, и я это поощряю. ⛔ **Замер бьёт по посылке задачи — стоп и вопрос, а не +артефакт под подпись.** Этот промт уже был исправлен четырежды по такому замеру. + +## 12. Прямой канал + +Механизм — `CLAUDE.md` §«Связь между сессиями»: файл `/tmp/textmachine-channel`, свой блок дописываешь +первым делом, чужие не трогаешь. ⚠ **Адрес из файла НЕ доказывает, что сессия жива: перед отправкой сверься +с `ListAgents`.** Эхо-протокол (§9) шли первым действием. **Нужной роли нет ⇒ канала нет, это НОРМАЛЬНЫЙ +случай: сессии подряд не опрашивать.** + +## 13. Критерий завершённости — проверяемый + +- У **каждого** пункта заказа — исход: сделано · не делаю с доводом · пинг. Сверка по СПИСКУ ЗАКАЗЧИКА (§5). +- Круги **сошлись**: последний не дал новых находок; прежние закрыты таблицей «находка → что сделано → + **чем предъявлено**». +- Гейт зоны (`make battery`) зелёный; названо, **что прогнано** и **сколько скипов** рядом с числом `ok`. + ⚠ `go test ./...` без `-v` скипы не печатает — «ноль скипов» и «скипы не показаны» неразличимы. +- Мутации: таблица полная, выжившие поимённо, новые записи помечены `battery`, каталог прогнан целиком. +- Числа сняты **после последней правки**; промежуточные не цитируются. +- Всё живое — **в ДЕРЕВЕ**, а не в письме. +- Явное **«работа завершена, править не планирую»**. Без него пак считается идущим. + +## Приложение. Ряды, на которые пак опирается + +Проверены мной по живому трекеру 17.09 (прибор прочёл 359 строк таблицы): + +| ряд | состояние | отношение к паку | +|---|---|---| +| **315** | ✅ **ЗАКРЫТ замером 06.09** | вход §4.1: `tmctl manifest` на ЭТОЙ книге уже дал 71 главу / 351 юнит / 356 чанков, `EXIT 0`, $0. Там же назван механизм `prompts_root` | +| **303** | открыт, «скоро» | вход §4.4 (TXT-половина); ⚠ его граница: проверено по коду и фикстуре, живая не-CJK книга через ингест не прогонялась | +| **283** | открыт, «скоро» | настоящий предмет §4.4 — структура глав для выдачи | +| **347** | открыт, «когда-нибудь» | §4.3/§4.9; ⚠ несёт устаревшие адреса `langpack.go`, пере-наведу я | +| **35** | открыт, «когда-нибудь» | §4.9: объясняет, почему снятие отказа не даёт банка | +| **260** | открыт, «скоро» | §4.5 — ложный `off_target` на латинице-тяжёлом русском ЭСКАЛИРУЕТ | +| **14** | открыт, «когда-нибудь», владелец | §4.8; ⚠ предупреждает о голден-фикстуре на коридоре | +| **79 · 81 · 259** | открыты | соседние предметы, не трогать | diff --git a/docs/BACKLOG.md b/docs/BACKLOG.md index 44d0923e..28e3def2 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). Здесь только долг и его диспозиции. -> - **СЧЁТ ОЧЕРЕДИ на 17.09 (скриптом по таблице — `python3 docs/scripts/counts.py`; обновлять при каждом лендинге):** всего **368** строк · зона бэкенд **195** строго / **248** широко (⚠ колонки счётчик читает С КОНЦА — испр. D39.116) · **блокеров очереди 0** (236 закрыта D39.175; **371** — актом D39.233, **360** — актом D39.232, обе 10.09), платные прогоны разблокированы · «скоро» **195** (перечень — грепом по таблице, рукописный список снят D39.126) · гейт-строка эксп-22: 153 (плюс 150 — руки владельца; ⚠ 55 из гейтов СНЯТА — D39.198 п.5); строка 5 — остаток гейчен ре-пробой 74, носитель события теперь строка 188 (аудит D39.140); остальное «когда-нибудь». ⚠ Счёт — НИЖНЯЯ граница долга, не потолок (разбор — легенда таблицы ниже). +> - **СЧЁТ ОЧЕРЕДИ на 17.09 (скриптом по таблице — `python3 docs/scripts/counts.py`; обновлять при каждом лендинге):** всего **369** строк · зона бэкенд **196** строго / **249** широко (⚠ колонки счётчик читает С КОНЦА — испр. D39.116) · **блокеров очереди 0** (236 закрыта D39.175; **371** — актом D39.233, **360** — актом D39.232, обе 10.09), платные прогоны разблокированы · «скоро» **196** (перечень — грепом по таблице, рукописный список снят 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; правки — только через оркестратора) @@ -274,7 +274,7 @@ | 343 | **`counts.py` ДЕРЖИТ РЕГИСТР ОДНИМ ПУТ�ём И НЕ ГЛОБИТ СЛАЙСЫ — предусловие нарезки `DEFECT_REGISTER.md`.** Вынос без этого молча уронит счёт открытых рядов, а гейт чисел покажет зелень: он читает ровно один файл. ⚠ План нарезки живёт в `docs/DOC_CLEANUP_PLAN.md` (Б14в) | доки | скоро | прибор читает регистр и его слайсы, счёт не меняется при выносе | вопросы платформы 07.09 | | **— ТЕХДОЛГ БЭКЕНДА: разбор research/33 (D39.224) —** | | | | | | | 346 | ⚠ **ПОЛОВИНА (а) ЗАКРЫТА 07.09 (`D39.225`): пин расхождения и паритет-тест стоят, оба под мутациями. ОСТАЁТСЯ (б) — фикс в окне перенарезки.** ⛔ **ПРАВИЛО ЗАГОЛОВКА РАЗЪЕХАЛОСЬ ПО ТРЁМ ПРЕДИКАТАМ, И «第零章» ЛОМАЕТ ПРОЛОГ — две половины с РАЗНОЙ ценой.** Страж длины живёт только в ингесте (`chunk/ingest.go:307`=`const chapterHeaderMaxRunes = 60` `chapterHeaderMaxRunes = 60`, применён `:323`; в `chunker.go` `RuneCountInString` — 0 хитов), осмысленность номера — только в чанкере (`backend/internal/chunk/chunker.go:315-317`=`v := section + num` — ⚠ испр. 16.09: было :316, где утверждение несёт строка с `||`, непригодной для ячейки таблицы `if !any || v <= 0`). Воспроизведено исполнением 07.09 (выброшенная проба на копии дерева): `第零章:序幕` ингест режет главой, а чанкер заголовок НЕ снимает — `heading=""`, сырой CJK-маркер уезжает модели; `parseSectionNumeral` на `零`/`0`/`〇` даёт `0,false` (контроль: `一`=1, `十二`=12); номера расходятся (`第一章` = `Chapter 2` при «Глава 1»); 84-рунный заголовок: ингест `false`, чанкер `ok=true`. ⚠ **Испр. 07.09 — без этой оговорки строка читается как ЛОЖНАЯ:** расхождение живёт ТОЛЬКО у заголовка С СЕПАРАТОРОМ после юнита (`第四章:…`); без сепаратора оба предиката дают `false` на любой длине, потому что такую строку отвергают и `isHeaderSeparator` ингеста, и `matchHeaderLine` чанкера. Пере-снято оркестратором на копии `d6dfc49`: с сепаратором 59 и 60 рун — оба `true`; 61 и 84 — ингест `false` при чанкере `ok=true n=4`; без сепаратора 12/55/59/60/61/84 — `false`/`false` во всех шести. Граница ровно `chapterHeaderMaxRunes` = 60. Перекрёстного теста нет ни в одном из 97 тестов `internal/chunk`. **(а) $0 СЕЙЧАС — пин ИЗВЕСТНОГО расхождения, а не паритет:** красный тест в `main` не ложится (`Makefile:58` `battery: build vet fmt lint test`), скип — класс D39.208; поэтому тест утверждает, что на `第零章` и на 61–84-рунной строке ингест и чанкер СЕГОДНЯ расходятся, назван этой строкой и краснеет ровно тогда, когда приземлится фикс (б), заставляя фиксера его перевернуть. Дизайн-пак 161 §4.5 паритет-тест ОПИСЫВАЕТ, пишет его пак стройки — пин (а) этому не мешает. **(б) В ОКНО ПЕРЕНАРЕЗКИ:** сам фикс меняет ТЕКСТ чанка ⇒ бампает `chunkerVersion` ⇒ снапшот обеих волн (`render.go:55-58` — «a deliberate re-translation»); отдельным актом он платит ту самую перепокупку, которую отменяет. ⚠ Ось «обязательность юнита» — НЕ трогать: носитель строка **303** (⚠ испр. 07.09: research/33 приписывал её `D39.207`, в теле ноты этого нет — греп по предмету 0 при 23 строках тела) | бэкенд | скоро для (а); (б) — в окне перекроя (шаг 3) | (а) пин расхождения · (б) сведение двух предикатов к ингестовским стражам внутри пака перекроя | research/33 Д3, research/27 §6 | -| 347 | **ПАР-ДАННЫЕ НЕЛЬЗЯ ЗАВЕЗТИ ПО ЧАСТЯМ: манифест требует ≥1 канал, и транслитерационный канал зашит в китайскую форму.** `lang/langpack.go:632`=`manifest declares no channel` — «manifest declares no channel — omit the file to ship all channels, or list at least one»; каналов два и они закрыты в Go (`source-morphology`, `transliteration`, `:108-114`), а `validate()` при `transliteration` требует ПОИМЁННО пиньинь-категории (`:521-527`); морфологический канал просит общие таблицы (`:507-516`) и в китайскую форму не зашит. Отказ жёсткий: при `gates.terminology.enabled` и `pack == nil` прогон отказывает `RefusalBadConfig` (`backend/internal/pipeline/runner.go:364`=`Gates.Terminology.Enabled` — ⚠ испр. 16.09: было :349), а в боевом `pipeline-c1.yaml:151`=`Роль ТЕРМИНОЛОГА (пак-20, D39.42 п.1)` гейт включён ⇒ вторая пара выбирает между фиктивными данными китайской формы и прогоном БЕЗ банка терминов (продуктовая цель №1). ⚠ **Триггер — первая новая ИСХОДНАЯ пара, и он РАНЬШЕ строки 115:** манифест лежит в `//` и хешируется языком-ИСТОЧНИКОМ (`langpack.go:252`), а 115 — про новую ЦЕЛЬ; ближайшая исходная пара в трекере — ja→ru (строка **81**), цель у неё ru. ⚠ **Пять строк снимают отказ, но банка на не-Han источнике НЕ дают** — детектора нет (строка **35**: en-детектор не существует, ja с zh-таблицами активно неверен); заказывать вместе, иначе строка обещает больше, чем покупает. Сегодня не оплачено ни разу: 0 `manifest.txt` в `configs/`, каталог пары один. ⚠ D39.64 П4 ратифицировала ОБРАТНОЕ намерение («источник без пиньинь-морфологии грузится без Palladius-файлов») — строка `list at least one` не дошла шаг до собственной цели | бэкенд | когда-нибудь (вход пака второй пары; триггер общий со строками 81 и 35) | разрешение нулевого числа каналов + решение по форме каналов | research/33 Д7, D39.64 П4 | +| 347 | **ПАР-ДАННЫЕ НЕЛЬЗЯ ЗАВЕЗТИ ПО ЧАСТЯМ: манифест требует ≥1 канал, и транслитерационный канал зашит в китайскую форму.** `backend/internal/lang/langpack.go:644`=`manifest declares no channel` — «manifest declares no channel — omit the file to ship all channels, or list at least one»; каналов два и они закрыты в Go (`source-morphology`, `transliteration`, `:108-114`), а `validate()` при `transliteration` требует ПОИМЁННО пиньинь-категории (`:533-539`); морфологический канал просит общие таблицы (`:519-529`) и в китайскую форму не зашит. Отказ жёсткий: при `gates.terminology.enabled` и `pack == nil` прогон отказывает `RefusalBadConfig` (`backend/internal/pipeline/runner.go:364`=`Gates.Terminology.Enabled` — ⚠ испр. 16.09: было :349), а в боевом `pipeline-c1.yaml:151`=`Роль ТЕРМИНОЛОГА (пак-20, D39.42 п.1)` гейт включён ⇒ вторая пара выбирает между фиктивными данными китайской формы и прогоном БЕЗ банка терминов (продуктовая цель №1). ⚠ **Триггер — первая новая ИСХОДНАЯ пара, и он РАНЬШЕ строки 115:** манифест лежит в `//` и хешируется языком-ИСТОЧНИКОМ (`backend/internal/lang/langpack.go:255`), а 115 — про новую ЦЕЛЬ; ближайшая исходная пара в трекере — ja→ru (строка **81**), цель у неё ru. ⚠ **Пять строк снимают отказ, но банка на не-Han источнике НЕ дают** — детектора нет (строка **35**: en-детектор не существует, ja с zh-таблицами активно неверен); заказывать вместе, иначе строка обещает больше, чем покупает. Сегодня не оплачено ни разу: 0 `manifest.txt` в `configs/`, каталог пары один. ⚠ D39.64 П4 ратифицировала ОБРАТНОЕ намерение («источник без пиньинь-морфологии грузится без Palladius-файлов») — строка `list at least one` не дошла шаг до собственной цели | бэкенд | когда-нибудь (вход пака второй пары; триггер общий со строками 81 и 35) | разрешение нулевого числа каналов + решение по форме каналов | research/33 Д7, D39.64 П4 | | 350 | ⚠ **ИСПОЛНЕНО 07.09 (`D39.225`) КРОМЕ ОДНОГО: по каждой из шести функций назван исход — четыре получили причину жизни комментарием («NO CALLER TODAY: contract surface waiting on backlog row 12»), дубль инлайна свёрнут в `finalStageName()`. ОСТАЁТСЯ словарь родов в четырёх носителях; текст его собственной ошибки врать перестал.** **РЕФАКТОРИНГ ОБЛЕГЧЕНИЯ ВЕДЕНИЯ (санкция владельца 07.09) — снапшот-нейтрально, и заказ здесь «решить», а не «удалить».** Вызовов вне определения ноль у шести функций (греп 07.09; КОНТРОЛЬ — `SplitChunks` 34 живых вызова): `obs.SafeGo`, `text.TokenizeCyrillic`, `CheapGateResult.UnitScaleHard`/`UnitScaleSoft`, `Bank.Voices()`, `Bank.Pairs()`. ⚠ **Четыре из шести стоят НАМЕРЕННО, и слепое удаление снимет намеренное:** `UnitScaleHard/Soft` сами называют, кого ждут — `checks/cheapgates.go:155-156`=`Total() is unchanged` «for the report and a future hard gate», то есть строку **12**; `TokenizeCyrillic` — образец паттерна value-default, на который ссылаются `checks/sanitizer.go:21`=`value-default pattern, like text.TokenizeCyrillic` и `:197`; `SafeGo` — намеренный контраст к `obs/panic.go`, названный решением `backend/internal/pipeline/waverun.go:420`=`NOT obs.SafeGo` — ⚠ испр. 16.09: было :405 («NOT obs.SafeGo»), и его удаление повесит два комментария в воздухе — класс строки **299**; `Voices`/`Pairs` (`membank/memory.go:371-376`=`address-register journal (frozen for` «frozen for the job») ждут потребителя, которого держит строка **13б**. ⇒ по каждой ОДИН исход с объявлением в отчёте: удалить ЛИБО назвать причину жизни в комментарии. Плюс ИМЯ последней стадии дважды одинаковым инлайном — `r.Pipeline.Stages[n-1].Name` — ⚠ **испр. 16.09: ДУБЛЬ УСТРАНЁН, предмет закрыт кодом:** оба места берут теперь общий хелпер (`backend/internal/pipeline/export.go:281`=`lastStage := r.finalStageName()` и `quality.go:485` тем же вызовом; инлайна `Stages[n-1].Name` в обоих файлах ноль, `finalStageName` по движку 4 вхождения). Прежний адрес был `pipeline/export.go:283` и `quality.go:342` (адреса на `d6dfc49`). ⚠ **Испр. 07.09: и research/33 §7.1, и первая редакция этой строки называли здесь «готовый `finalStageWave()`» — это ДРУГАЯ функция**: она возвращает ВОЛНУ (`snapshot.go:247`, вызовов 13 — 10 прод и 3 теста), а хелпера для ИМЕНИ не существовало вовсе, и «при готовом хелпере» читалось как «работа уже сделана» и словарь родов в четырёх носителях (`membank/memory.go`, `membank/memseed.go`, `backend/internal/terminology/classify.go:40`=`Genders is the closed vocabulary` — ⚠ испр. 16.09: было :50, промт), где текст собственной ошибки врёт о принимаемом множестве. ⛔ Границы санкции: НЕ дробить `internal/pipeline` и НЕ переписывать `Runner` (`12-go-style-notes.md` §1, D39.23), ничего, что двигает снапшот / хеш запроса / ключ манифеста. ⚠ Адреса сняты research/33 на `e69902a`, а лендинг 07.09 тронул `memseed.go` и `export.go` — пере-снимать командой, не по тексту | бэкенд | когда-нибудь | попутный проход с батареей + объявление исхода по каждой функции | research/33 §7.1, санкция владельца 07.09 | | 351 | **ЛИНТ СЛОВАРЯ КЛАССИФИКАТОРА ПИНИТ ОДНО НАПРАВЛЕНИЕ: слово, УБРАННОЕ из Go, не ловит ничто.** Гейт `TestEveryClassifierPromptSpeaksTheEnginesVocabulary` (лендинг `D39.225`) утверждает «каждое слово из `terminology.Types`/`Genders` названо в промте пары» — и потому сжимается вместе со своим предметом: выкинутый класс `title` оставляет батарею зелёной (замер 07.09 на копии: 19 ok / 0 FAIL). Вырожденный предел закрыт стражем `len(classifierVocabulary()) == 0`, общий случай — нет. Настоящий дом — пин САМОГО словаря, которого в репозитории нет (research/33 Д1: 0 тестов на `terminology.Types`). ⚠ Граница названа зоной самостоятельно, в заказ пака не входила | бэкенд | когда-нибудь | пин словаря (голден или рефлексивный тест) | `D39.225`, research/33 Д1 | | 352 | **ПЯТЬ РУКОПИСНЫХ СПИСКОВ АРМ-КОНФИГОВ ЖИВУТ РЯДОМ С ДВУМЯ ГЕЙТАМИ, КОТОРЫЕ ТЕПЕРЬ ГЛОБЯТ.** `pipeline/promptlabel_test.go:45`=`pipeline-arm-glm.yaml` · `config/echoregen_shipping_test.go:35`=`pipeline-arm-glm.yaml` · `config/content_labels_test.go:529`=`pipeline-c1.yaml` и `:575` · `config/prompt_pack_test.go:239`=`pipeline-arm-mistral.yaml` перечисляют армы поимённо; новый арм автоматически попадает в `TestAnArmIsTheProductionConfigWithADifferentEditor` и `TestSwapArmConfigs` и проходит мимо всех пяти. Найдено приёмкой `D39.225`, вне заказа пака; предсуществующее | бэкенд | когда-нибудь (со следующим касанием армов) | свести пять списков к глобу | `D39.225` | @@ -404,3 +404,4 @@ | 493 | **ХАРНЕСС МУТАЦИЙ ЗОНЫ ЗАСЧИТЫВАЕТ ВЫЖИВШЕЙ ПОСАДКУ, ЧЕЙ ШАБЛОН `-run` НЕ ВЫБРАЛ НИ ОДНОГО ТЕСТА.** `platform/tools/mutate.py`, `verdict()`: ветка `if code == 0` возвращает «выжила» безусловно, не спрашивая, запускался ли пин вообще; `baseline()` гоняет тот же набор и требует нулевого кода, поэтому пустой шаблон проходит базу ЗЕЛЁНЫМ и после посадки засчитывается выжившей. ⚠ **Направление ошибки безопасное** — лишняя «дыра», а не лишняя «поимка», — и числа пака, который харнесс строил, не испорчены: замерено оркестратором, что все 26 якорей каталога встречаются в дереве ровно по разу и записей с несуществующим пином ноль. ⛔ Но фикстурный каталог самого харнесса несёт ШЕСТЬ форм исхода (пойман пином · красное другим тестом · выжила · якоря нет · база красная · пина нет), и седьмой — «шаблон не выбрал ни одного теста» — среди них НЕТ, то есть собственный пин прибора этого класса не стережёт. Родня ряда **486**, которым прибор и построен: там лечилось «любое красное засчитывается поимкой», здесь остаётся зеркальное «любое зелёное засчитывается выживанием» | платформа | скоро | пустой шаблон `-run` даёт исход «НЕ ИЗМЕРЕНА», и это запинено седьмой формой фикстурного каталога | линза приёмки 17.09, подтверждено чтением `verdict()` | | 494 | **ФИКСТУРА ПРЕДЕЛА ПЕРЕЗАПУСКОВ ДЕРЖИТ ТРАТУ НУЛЁМ — ПИН ОТЧИТЫВАЕТСЯ ЗА КЛАСС, А МЕРЯЕТ СРЕЗ.** Все четыре денежных пина капа в `platform/internal/runs/attemptcap_test.go` гоняют `f.engine.set(… Spend: usd(0))` при `f.runner.alive = false`, поэтому утверждение «холд вернулся целиком» осмысленно ровно на НУЛЕВОЙ трате. Класс «предел сработал на прогоне, который УЖЕ что-то потратил» идёт другой веткой расчёта и не измерен ничем: пинов капа на ненулевой трате в зоне нет. ⚠ Это не дефект пака — поведение при нуле верно и запинено, — а НЕПОЛНОТА, названная приёмкой и принятая зоной в её же блок «где прибор слеп». Норма, под которую ряд заводится: если фикстура держит что-то постоянным, пин отчитывается за КЛАСС, а меряет СРЕЗ, и молчит о том, какой именно | платформа | скоро | предел перезапусков запинен на прогоне с ненулевой тратой, либо утверждение пина сужено до среза, который он действительно меряет | линза приёмки 17.09, пере-снято оркестратором | | 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` | diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md index 4be9e8cc..29b72410 100644 --- a/docs/PROGRESS.md +++ b/docs/PROGRESS.md @@ -1,6 +1,6 @@ # Журнал прогресса -> **⟶ ТЕКУЩЕЕ СОСТОЯНИЕ** (на 2026-09-17, голова D39.265 — КУРС: движок и платформа до «работает и отдаёт результат», фронт ЗАМОРОЖЕН и P7 его НЕ размораживает (D39.147). **ОЧЕРЕДЬ №23** (единственный носитель — здесь; роль передана 06.09, №22 закрыт нотой передачи D39.217; ⚠ испр. 06.09: коммит передачи `c992ee5` бампнул голову и НЕ тронул номер — гейта на номер очереди нет вовсе, `counts.py` сверяет только голову, поэтому носитель разошёлся молча). ⚠ **ЗАКАЗ ВЛАДЕЛЬЦА 01.09 — ИСПОЛНЕН, испр. 08.09 (висел как «первым» неделю после исполнения):** (0а) ревизия документации на протухшее ОТРАБОТАНА 01.09 воркфлоу `docs-staleness-revision-A` (15 срезов), провенанс находок — `D39.185`; (0б) планы доработок в бэкенд и платформу — исполняются ПАКАМИ, за 07–08.09 закрыты два движковых (`D39.225`, `D39.226`); (0в) вынос неактуального в архив идёт батчами `DOC_CLEANUP_PLAN.md` (Б14/Б15/Б17 живы). ⇒ строка ниже — не заказ, а история: (0а) ревизия документации на ПРОТУХШЕЕ — по всем зонам; (0б) планы доработок в БЭКЕНД и ПЛАТФОРМУ; (0в) вынос неактуального в АРХИВ (`docs/archive/`, `platform/docs/archive/`) — за сутки 31.08 закрыто много, и часть носителей стала историей. ⚠ Трезвость по масштабу (пере-считано 02.09): **95** живых доков в `docs/` (⚠ испр. 17.09 вечером: стояло **98**, и это был ЛОЖНЫЙ литерал, а не потеря файлов — сверка дерева со срезом головы предписанной здесь же командой дала 95 в ОБЕИХ сторонах, ни одного файла не ушло и не пришло; ошибся сам пере-счёт, а прибор это число не сторожит и потому ложь прожила день. В 95 уже входит промт выдачи №14; пере-счёт после выноса каталога консилиума; прежние 97 разошлись с фактом 144 и это заметил ревизор, а не гейт) (пере-счёт 04.09: `find docs -name '*.md' -not -path 'docs/archive/*' | wc -l`), 8 в `platform/docs`, **12** в `backend/docs`, **7** в `frontend/docs` (испр. 17.09: стояло 9) — ⚠ ⚠ испр. 11.09: из 97 ВРЕМЕННЫХ **три** (`DOC_CLEANUP_PLAN`, живой до закрытия батчей Б14/Б15/Б17); два прежних временных уехали в `archive/reports/` 02.09; счёт бэклога — бюллетенем ниже, открытых рядов регистра платформы — 110 (major 1) (major 1), всего рядов 469 (пере-счёт `python3 docs/scripts/counts.py`; с 04.09 оба числа под гардом `--check`, прежние 95/3 разошлись молча) ⚠ (ревизией 02.09 ряды **154** и **157** переведены из «скоро» в «когда-нибудь»: их гейтом стоял первый холодный прогон, он ОТРАБОТАЛ 31.08 и оба предусловия оказались другими — разбор в самих ячейках, ни одна НЕ закрыта). ⚠ Числа доков `counts.py` НЕ сторожит — при переносе файлов пере-считывать руками командой `find docs -name '*.md' -not -path 'docs/archive/*' | wc -l`. ⚠ И предупреждение о МЕТОДЕ, купленное сменой №21: «выглядит протухшим» ≠ «протухло». Три факта оркестратора опровергнуты ЗАМЕРОМ сессий, а якоря `15-money-path.md` в девяти случаях из двенадцати РОДИЛИСЬ верными и сгнили дрейфом — то есть ревизия обязана быть исполнением, а не чтением. ⚠ **ОЧЕРЕДЬ, унаследованная от №21** (три лендинга 31.08 — секция «СОСТОЯНИЕ ПАКОВ» ниже): **(1) ~~РАЗРЫВ ЦИКЛА~~ ЗАМКНУТ ЖИВЬЁМ 04.09** — пользователь получил EPUB настоящего ПЛАТНОГО перевода ЧЕРЕЗ API, `epubcheck` 5.3.0 на СКАЧАННОМ файле 0/0/0/0 (книга `bk_SS5VES2JELESJSTR`, потрачено $0.278319 из гранта $0.60 при потолке пака $1.5, санкция D39.189). Дверь выдачи построена и проверена исполнением: `202`+`Location`, поллинг с `Retry-After`, Range 206 · второй клиент 200 · аноним 401 · чужая книга 404, TTL с GC, идемпотентность третьего создающего вызова. Все ТРИ сценария строки 216 предъявлены живьём (подпись банка · halt на потолке с exit 4 · `409 run_not_resumable/ceiling_reached` и лечение новым прогоном). +> **⟶ ТЕКУЩЕЕ СОСТОЯНИЕ** (на 2026-09-17, голова D39.266 — КУРС: движок и платформа до «работает и отдаёт результат», фронт ЗАМОРОЖЕН и P7 его НЕ размораживает (D39.147). **ОЧЕРЕДЬ №23** (единственный носитель — здесь; роль передана 06.09, №22 закрыт нотой передачи D39.217; ⚠ испр. 06.09: коммит передачи `c992ee5` бампнул голову и НЕ тронул номер — гейта на номер очереди нет вовсе, `counts.py` сверяет только голову, поэтому носитель разошёлся молча). ⚠ **ЗАКАЗ ВЛАДЕЛЬЦА 01.09 — ИСПОЛНЕН, испр. 08.09 (висел как «первым» неделю после исполнения):** (0а) ревизия документации на протухшее ОТРАБОТАНА 01.09 воркфлоу `docs-staleness-revision-A` (15 срезов), провенанс находок — `D39.185`; (0б) планы доработок в бэкенд и платформу — исполняются ПАКАМИ, за 07–08.09 закрыты два движковых (`D39.225`, `D39.226`); (0в) вынос неактуального в архив идёт батчами `DOC_CLEANUP_PLAN.md` (Б14/Б15/Б17 живы). ⇒ строка ниже — не заказ, а история: (0а) ревизия документации на ПРОТУХШЕЕ — по всем зонам; (0б) планы доработок в БЭКЕНД и ПЛАТФОРМУ; (0в) вынос неактуального в АРХИВ (`docs/archive/`, `platform/docs/archive/`) — за сутки 31.08 закрыто много, и часть носителей стала историей. ⚠ Трезвость по масштабу (пере-считано 02.09): **95** живых доков в `docs/` (⚠ испр. 17.09 вечером: стояло **98**, и это был ЛОЖНЫЙ литерал, а не потеря файлов — сверка дерева со срезом головы предписанной здесь же командой дала 95 в ОБЕИХ сторонах, ни одного файла не ушло и не пришло; ошибся сам пере-счёт, а прибор это число не сторожит и потому ложь прожила день. В 95 уже входит промт выдачи №14; пере-счёт после выноса каталога консилиума; прежние 97 разошлись с фактом 144 и это заметил ревизор, а не гейт) (пере-счёт 04.09: `find docs -name '*.md' -not -path 'docs/archive/*' | wc -l`), 8 в `platform/docs`, **12** в `backend/docs`, **7** в `frontend/docs` (испр. 17.09: стояло 9) — ⚠ ⚠ испр. 11.09: из 97 ВРЕМЕННЫХ **три** (`DOC_CLEANUP_PLAN`, живой до закрытия батчей Б14/Б15/Б17); два прежних временных уехали в `archive/reports/` 02.09; счёт бэклога — бюллетенем ниже, открытых рядов регистра платформы — 109 (major 0), всего рядов 469 (пере-счёт `python3 docs/scripts/counts.py`; с 04.09 оба числа под гардом `--check`, прежние 95/3 разошлись молча) ⚠ (ревизией 02.09 ряды **154** и **157** переведены из «скоро» в «когда-нибудь»: их гейтом стоял первый холодный прогон, он ОТРАБОТАЛ 31.08 и оба предусловия оказались другими — разбор в самих ячейках, ни одна НЕ закрыта). ⚠ Числа доков `counts.py` НЕ сторожит — при переносе файлов пере-считывать руками командой `find docs -name '*.md' -not -path 'docs/archive/*' | wc -l`. ⚠ И предупреждение о МЕТОДЕ, купленное сменой №21: «выглядит протухшим» ≠ «протухло». Три факта оркестратора опровергнуты ЗАМЕРОМ сессий, а якоря `15-money-path.md` в девяти случаях из двенадцати РОДИЛИСЬ верными и сгнили дрейфом — то есть ревизия обязана быть исполнением, а не чтением. ⚠ **ОЧЕРЕДЬ, унаследованная от №21** (три лендинга 31.08 — секция «СОСТОЯНИЕ ПАКОВ» ниже): **(1) ~~РАЗРЫВ ЦИКЛА~~ ЗАМКНУТ ЖИВЬЁМ 04.09** — пользователь получил EPUB настоящего ПЛАТНОГО перевода ЧЕРЕЗ API, `epubcheck` 5.3.0 на СКАЧАННОМ файле 0/0/0/0 (книга `bk_SS5VES2JELESJSTR`, потрачено $0.278319 из гранта $0.60 при потолке пака $1.5, санкция D39.189). Дверь выдачи построена и проверена исполнением: `202`+`Location`, поллинг с `Retry-After`, Range 206 · второй клиент 200 · аноним 401 · чужая книга 404, TTL с GC, идемпотентность третьего создающего вызова. Все ТРИ сценария строки 216 предъявлены живьём (подпись банка · halt на потолке с exit 4 · `409 run_not_resumable/ceiling_reached` и лечение новым прогоном). > ⛔ **ПЯТЬ ПОТОКОВ РАБОТЫ — состояние на 07.09 (пере-снято лендингами смены №23).** > **(1) ПОЛИГОН — «ремонт прибора»** (`docs/POLYGON_INSTRUMENT_REPAIR_SESSION_PROMPT.md`, строки 319 · 300 · 265 · 143): > ⚠ **ЕДИНСТВЕННЫЙ ПОТОК, НЕ СДВИНУВШИЙСЯ ЗА СМЕНУ — сессия по промту так и не стартовала.** Блокирующая линза @@ -221,6 +221,356 @@ ⚠ Ниже точки реза якорей не было ни одного (пере-снято прибором перед выносом), так что больше у вас ничего не сдвинулось. +#### ОТЧЁТ пака «РЕШЁННОЕ НЕ ПЕРЕ-СПРАШИВАЕТСЯ» (17.09, сессия `textmachine-main-57`). НЕ КОММИЧУ — дерево передаю оркестратору №23 + +**Деньги пака: $0.** Платных вызовов моделей не было ни одного. Прибор M1 открывает раннер ЧИТАЮЩИМ путём +(`openRunner` с `forWrite=false`), который `models.CheckKeys` не зовёт вовсе, и не вызывает ни +`runTerminologist`, ни `runClassifier`, ни `TranslateBook`. Купленное сырьё открывалось только копиями. + +##### 1. Исход по КАЖДОМУ пункту заказа + +| пункт промта | исход | чем предъявлено | +|---|---|---| +| §4.1 замер M1 | **сделано**, форма предиката принята оркестратором | `backend/internal/pipeline/bankbasis_m1_probe_test.go`; числа §3 | +| §4.2 базис — ИСТОЧНИК ОТВЕТОВ, не фильтр | **сделано** | пин `TestTheBasisCarriesTheBoughtAnswerRatherThanDroppingIt` сравнивает ЧЕТВЁРКУ (dst, status, type, gender) авто-банка | +| §4.2 таблица читателей | **сделано, и один читатель был пропущен** — найден адверсариальным кругом, см. §4б | `TestTheBankedTypeReachesTheSheetWhenTheBasisAnswers` | +| §4.2 развилка «судятся ли базисные ответы проверками спора» | **решено: ДА**, довод механизменный | `backend/internal/membank/memseed.go:888`=`if IsEngineUnsigned(b) && b.Src == c.Src` | +| §4.2 `Invented` и очередь спорных | **сделано, решено раздельно, ЗАПИНЕНО** | `TestTheThreeDeclaredDecisionsAboutABasisRowAreGuarded` | +| §4.3 две границы записи и порядок | **сделано** | `backend/internal/pipeline/mining.go:277`=`r.writeBankBasis(ctx, "bank-mining/signature-stop")` перед памятью флажка; `backend/internal/pipeline/bookrun.go:262`=`r.writeBankBasis(ctx, "run-finished")` | +| §4.3 неудача записи КРИЧИТ | **сделано** | `ERROR` с названной ценой, прогон не роняется | +| §4.4 форма отпечатка | **сделано, сильнее заказанного** | окна по ВСЕМ вхождениям; ширина — ОТДЕЛЬНОЕ пар-данное `basis_width` | +| §4.4 сторож растущей книги | ⛔ **НЕ ДЕЛАЮ, с замером** — §6 | числа роста в §3 | +| §4.5 условие «решено» + пин посылки ряда 487 | **сделано** | `TestBasisServesOnlyADecidedRow`, подтест `status auto WITH a rendering (backlog row 487)` | +| §4.5 юниты | **отдельный проход над ВСЕМИ кандидатами**, батчер не тронут | `TestBasisUnitsGiveEveryCandidateAUnitOfItsOwn`; `CONTROL-2` печатает байты батчей | +| §4.6 носитель | **таблица**, миграция v19 | `backend/internal/store/bankbasis.go:26`=`func (s *Store) BankBasisForBook` | +| §4.7 поле контракта | **сделано, аддитивное; ПОЛОВИНА из двух** — §9 п.6 | `settled_earlier` в сводке и построчно | +| §4.7 три лгущие фразы | **сделано** | своя фраза `SETTLED EARLIER`; `NOT ASKED` оставлена — для банк-снятых строк она ВЕРНА | +| §4.8 ряд 490 страж разрыва окон | **сделано, $0** | `backend/internal/membank/memvoice.go:426`=`func TermWindowGaps` | +| Ряд **130** (строка 395 промта: «Строит: **130** · **490**») | ⛔ **ЦЕЛЬ ДОСТИГНУТА ДРУГИМ МЕХАНИЗМОМ, ряд НЕ закрыт** — разбор сразу под таблицей | замер по трём предметам остатка при знаменателе 1153 | +| §4.8 ряд 447 | ⛔ **НЕ ДЕЛАЮ, с замером** — §6 | | +| §4.8 ряд 448 | **сделано, объявлено сменой поведения** | голден 144 → 149 строк | +| §4.9 вне скоупа | не трогал | | +| Приложение: онтологию правит пак базиса | **сделано** | `docs/architecture/18-bank-ontology.md:25`=`**ПАМЯТЬ РЕШЕНИЙ** — что книга уже решила` | + +⛔ **РЯД 130 — исход ТРЕТЬЕГО рода, и первая редакция этого отчёта не называла его вовсе.** Ряд заказан +промтом наравне с 490 («Строит: **130** · **490**»), а §13 требует исход по КАЖДОМУ пункту — то есть +заказанный пункт стоял без утверждения, и нашлось это вопросом оркестратора, а не мной. ⚠ Второй случай +одного класса за смену: **оба раза дыра была не в неверном числе, а в ОТСУТСТВУЮЩЕМ утверждении** (первым +был прибор, не названный прибором, §8). Числа я проверяла, полноту перечня — нет. + +**Что пак с ним сделал — замер, а не проза** (знаменатель: изменённых строк зоны прочитано **1153**): + +| предмет остатка ряда 130 | изменённых строк пака | +|---|---| +| `writeAutoBank` · `emitRankCap` — накопительный мердж авто-банка | **0** | +| `seedReject` · `mined-rejects` — освобождение слотов | **0** | +| `memory_version` / `MemoryVersion` | **0** | + +⇒ **Замысел ряда исполнен, механизм ряда НЕ построен, и не построен НАМЕРЕННО.** Ряд предлагал держать +решение между покупками накопительным мерджем авто-банка, а тот двигает банк → `memory_version` — потому +ряд и висит СТОП-решением владельца. Базис даёт то же свойство (слово владельца 16.09, `D39.254` п.1: +«решение банка между покупками ДЕРЖИМ») **отдельной аддитивной таблицей, которая банк не трогает вовсе** +(миграция v19). ⇒ гейт стоп-решения этим паком **не достигается по построению**, и закрывать ряд нельзя: +остаток сузился до ДВУХ названных предметов — накопительный мердж и слоты seed-rejects, — а само +стоп-решение как было, так и остаётся за владельцем. + +##### 2. ⛔ СМЕНА ПОВЕДЕНИЯ — подаю ратифицируемо, отдельным пунктом + +**Что изменилось.** Первый прогон книги после появления базиса платит ОДИН раз за переупаковку хвоста +батчей. Замерено по четырём прогонам одной фикстуры: run1 `$0.001820` · **run2 `$0.001820`** · +run3 `$0.000000` · run4 `$0.000000`; вызовов провайдера банк-ролью 1 → 2 → 2 → 2. + +**Механизм.** Базис — ТРЕТИЙ вход состава батчей, и он переходит из пустого в полный на выходной границе +run1. Run2 встречает состав, которого у run1 не было, не находит чекпойнта по хешу запроса и покупает пасс. +⛔ Лечение «встать в сторону у книги, которая уже платила» — ровно тот баг, который докблок +`dropBankSettled` описывает своими словами: **правило, решающее иначе на втором прогоне, не есть правило +резюма**. Цена ограничена `gates.terminology.budget_usd` и ОБЪЯВЛЕНА сообщением ряда 448. + +**Какие тесты описывали ЭТУ смену поведения и куда уехала гарантия — ТРИ, и это первые три строки §5:** +`TestAResumeFindsItsCheckpointsAfterTheFilter` · `TestTheRunTotalIsThisRunsSpendIncludingTheClassifier` · +`TestAutoWireIsDeterministicAndDoesNotMoveTheDraftWave`. Все три утверждали «резюм бесплатен с ПЕРВОГО +раза»; теперь утверждают «со второго», и каждый обслужен так, что стал СИЛЬНЕЕ прежнего, а не слабее. +⚠ **Таблица §5 шире — в ней СЕМЬ строк, и остальные четыре к смене поведения отношения не имеют:** две +двигает голова схемы 18 → 19 (`TestRowsWrittenBeforeTheThinkingColumnReadAsUnanswered` и +`migrate_cli_test.go`), одну — рост поля проекции (`TestEveryDecidingFieldSurvivesTheProjection`), и одна +это голден операторских сообщений под пере-формулировку ряда 448. Названо раздельно, потому что «три» и +«семь» в одном отчёте без этой фразы читаются как расхождение, и приёмке пришлось бы угадывать, какое +число о чём. + +##### 3. ЧИСЛА — все сняты ПОСЛЕ последней правки, каждое с командой + +Команда (подготовка материала — в докблоке прибора, `bankbasis_m1_probe_test.go:28`, включая шаг, которого +прогону A не хватает в архиве): +`TM_BASIS_M1=<копия A>,<копия B> go test ./internal/pipeline/ -run TestProbeBankBasisM1 -v` + +| | кандидатов | предложено базису | банк-фильтр взял | **обслужено** | пере-спрошено | класс | +|---|---|---|---|---|---|---| +| A `bk_ROEHZBD46ALFI43E` | 69 | 68 | 1 | **67 (97 %)** | 1 | `signed-by-owner` | +| B `bk_NH6275ZIRFFTLZHG` | 66 | 65 | 1 | **64 (97 %)** | 1 | `signed-by-owner` | + +Прочие классы пере-спроса на неизменном исходнике — НОЛЬ, включая новый `ambiguous-surface`. + +**Верность реконструкции (ассерт, не лог):** A — 69 против 69, B — 66 против 66, расхождений 0 в обе стороны. + +**Контроли, все различающие:** +- **К-1:** множество пере-спрошенных совпало с НЕЗАВИСИМЫМ позиционным обходом окон — `missing=0 extra=0`. +- **К-2:** состав батчей байт-идентичен, печатается РАЗМЕР рендера (910 и 903 байта). +- **К-3 (сверх заказа):** `kwic_per_term 3→1`, `3→40`, `kwic_width 40→120` теряют **0, 0, 0**; + положительный контроль `basis_width 40→80` теряет **ВСЕ** (67 и 64). + +**Цена правила юнита:** A и B — по **1** кандидату, и это подписанная строка. С экземпцией подписи (решение +оркестратора) все четыре варианта правила дают одно число ⇒ на этом материале правило БЕСПЛАТНО. +Форма юнитов: A — 54 юнита, 44 одиночки, крупнейший 4; B — 52, 43, 4. + +**`auto`-хвост (§5 п.5 промта):** **A — 0, B — 0**, с гистограммой статусов рядом (`approved:2 draft:67` и +`approved:2 draft:64`, строк без ряда банка 0). ⇒ на этом материале класс **не измерен, а не отсутствует**. + +**Растущая книга:** базис пишется на префиксе (главы 1–2, 4 чанка из 6, 17199 из 23768 байт): + +| | решено на префиксе | пережило рост | пере-спрошено | своя улика выросла | держит юнит | +|---|---|---|---|---|---| +| A | 67 | **37 (55 %)** | 30 | 29 | 1 | +| B | 64 | **32 (50 %)** | 32 | 29 | 3 | + +**Остаток «стык чанков» — ИЗМЕРЕН, а не назван:** бюджет сегментации ×0.5 (чанков 6 → 11) двигает отпечаток +у **6 из 69** (A) и **8 из 66** (B); ×2.0 (6 → 3) — у **4** и **4**; все кандидаты в исходнике +засвидетельствованы. ⇒ двукратная смена кроя стоит **6–12 %** пере-спроса, а не книги. + +##### 4. Находки о МЕТОДЕ — мои собственные, по ходу работы + +⛔ **(1) НУЛЕВОЕ ЗНАЧЕНИЕ КАК НОМЕР ЮНИТА.** `MergeUnits` возвращает ЧАСТИЧНУЮ карту, а движковая конвенция +читает отсутствие ключа как «одиночка». Предикат индексировал её напрямую ⇒ все безюнитные кандидаты +получали id **0**, то есть ОДИН юнит на 44 члена. Прибор печатал **22 из 69** и целую историю про то, что +правило юнита съедает две трети экономии. Поймано НЕСОГЛАСИЕМ ДВУХ ЗАМЕРОВ об одном правиле. Класс общий и +дороже числа: **частичная карта, чьё отсутствие ключа читается как значение.** + +⛔ **(2) ВАРИАНТ ЗАМЕРА, НЕ ИСПОЛНЯЮЩИЙ СОБСТВЕННОЙ ПОДПИСИ** — строка «подписанные считаются решёнными» +не меряла ничего: предикат отвергал строку по СТАТУСУ, и юнит оставался заблокирован. Печатала то же число, +что строка над ней, и читалась как находка. + +⛔ **(3) КОНТРОЛЬ БЫЛ НЕПРАВ, И ЭТО ДОКАЗАНО ВТОРЫМ МАРШРУТОМ.** Первая редакция К-1 требовала «ровно +виновник и его юнит» и покраснела на живом материале: правка — это ТОЧКА, и она попадает в окно улик всякой +поверхности рядом, включая те, что виновник СОДЕРЖИТ (`三转蛊师` содержит `蛊师`). Новая редакция сверяет +предикат с НЕЗАВИСИМЫМ позиционным обходом окон — 0/0 в обе стороны. + +⛔ **(4) МОЙ РАЗДЕЛ ТЕСТА УВЁЛ ЛОВЦА ИЗ-ПОД ЗАПИСИ КАТАЛОГА — нашёл ПОЛНЫЙ прогон.** Разделив денежный +тест, я перенесла его резюм-ногу в новый тест; запись `BANKMONEY-…-cumulative-spend` осталась смотреть на +старый. Тест зелёный, раздел объявлен заранее, прицельный прогон моих записей 15/15 RED — и мутация ВЫЖИЛА. +**Ни один способ дешевле полного прогона этого не видел.** Запись нацелена на обоих ловцов. + +⛔ **(5) РЕФАКТОР ЕДВА НЕ ОТПРАВИЛ В ОТСТАВКУ ЧУЖОЙ ДЕНЕЖНЫЙ ПИН, и это моя ошибка второго рода.** Чиня (4), +я свела три копии пере-ранжирования в один хелпер — код стал лучше, а чужая запись +`MONEY-the-rescoring-is-applied-to-the-filtered-copy` перестала резолвиться: она сажает мутацию в ЛИТЕРАЛЬНЫЕ +три строки. Пере-нацелив её на хелпер, я получила **выжившую** — потому что внутри хелпера нет отфильтрованной +копии, и посадка стала «не пере-ранжировать вовсе», то есть ДРУГИМ дефектом, который никто не пинит. +⇒ **откатила рефактор в обоих пред-существующих местах и восстановила чужую запись байт-в-байт из HEAD**; +хелпер остался только у моего нового вызывающего и объясняет в комментарии, почему НЕ поглотил соседей. +Норма, которую это купило: **рефактор, уводящий предмет пина из-под его посадки, тихо отправляет пин в +отставку — и «улучшение кода» здесь не довод.** + +##### 4б. Адверсариальный круг по СВОЕЙ готовой работе (§5 промта) — 9 находок, все подтверждены моим чтением + +Контролёр поднят один, по §5 промта. Каждую находку я пере-проверил сам, прежде чем принять; ни одна не +отвергнута. + +| находка | класс | что сделано | чем предъявлено | +|---|---|---|---| +| **ТИП из базиса не доезжает до ЛИСТА:** слияние стоит ПОСЛЕ `applyTypes`, поэтому на листе `place`, а в банке того же термина `term` — в установившемся режиме | мажор; пропущенный читатель (ровно то, о чём предупреждал §4.2) | базисный тип штампуется на кандидатов ДО листа, отдельной функцией, чтобы не раздуть `reclassified` | `TestTheBankedTypeReachesTheSheetWhenTheBasisAnswers` + запись `BASIS-banked-type-never-reaches-the-sheet` | +| **`EvidenceWindows` КВАДРАТИЧЕН:** `window()` пере-строит рунный вид ВСЕЙ книги на каждое вхождение; ×4 исходник → ×15 времени | мажор; вдобавок новый вызывающий молча снял условие ЧУЖОГО вывода («strings are chunk-sized») | источник конвертируется в руны ОДИН раз; равенство окон с `window()` запинено отдельно | `TestEvidenceWindowsDoesNotGrowQUADRATICALLY…` (ratio ×3.2 при ×4) + `TestEvidenceWindowsCutsTheSameWindowAsKWIC` | +| **ПОДПИСАННАЯ строка получала запись в базис:** снимут подпись — базис подаёт слово движка поверх слова владельца | мажор; вторая петля, которую онтология объявляет защищённой | запись отказана при `status == "approved"`; текст онтологии приведён в соответствие | `TestTheOwnersSignedRowIsNeverRecordedInTheBasis` + запись `BASIS-records-the-owners-signed-rendering` | +| **Индекс банка СХЛОПЫВАЛ (src, sense, since, until) в один src:** побеждала последняя строка, подпись на одном окне становилась невидимой | мажор; **второй случай класса «нулевое/отсутствующее читается как значение»** | неоднозначная поверхность ОТКАЗАНА, а не угадана: свой класс `ambiguous-surface`, отказ и на чтении, и на записи | `TestAnAmbiguousSurfaceIsReAskedRatherThanGuessed` + запись `BASIS-collapses-two-senses-of-one-surface` | +| **Один кандидат мог нести ОБЕ метки** (`never_asked` и `settled_earlier`): две взаимоисключающие фразы на листе, двойной счёт, и — хуже всего — вынос из очереди спорных по `SettledByBank` | средний, но следствие денежное | базису предлагаются ТОЛЬКО кандидаты, которых не взял банк-фильтр | `TestASettledRowIsNotAlsoMarkedNeverAsked` + запись `BASIS-and-the-bank-filter-claim-the-same-row` | +| **`basis_width` — пар-данное, которым пак отвечает на ревью-вопрос канона, — не стерёг НИКТО:** мутация «читать `kwic_width`» выжила весь тест-набор | средний; пин гонял только ветку ДЕФОЛТА | пин с настоящим паком | `TestBasisWidthIsReadFromThePairWhenThePairStatesIt` + запись `BASIS-width-read-from-the-prompt-knob` | +| **Три объявленных решения не ловило ничто** (подавление `Invented`, отказ от экземпции в очереди спорных, порядок разбора меток) — все три посадки выжили | средний ×3; «объявлено в комментарии» ≠ «стережётся» | один пин на три, каждое с контролем | `TestTheThreeDeclaredDecisionsAboutABasisRowAreGuarded` + три записи каталога | +| **Строка прибора «(the design)» НЕ была дизайном:** её `count()` блокировал юнит на `basisSigned`, а движок его исключает ⇒ печаталось 62 там, где движок даёт 64 | средний; ровно класс, который запрещает докблок этой же функции | вариант исполняет свою подпись; строки переименованы | строки `UNIT-RULE` в §3 | +| **Рецепт в докблоке прибора КРАСНЫЙ на этой машине** для прогона A (в архиве нет `mirror/prompts`) | минор, но делает половину замера невоспроизводимой | рецепт дополнен шагом сборки, с доводом, что это ВОССТАНОВЛЕНИЕ архива, а не выбор входа | докблок `bankbasis_m1_probe_test.go:28` | + +Плюс три минора прозы, закрытые: «`basisWidth` mirroring `terminologyOpts`» (у него ДВЕ ступени, не три, и +это намеренно), «банк читается ОДИН раз за роль» (пред-существующее второе чтение в `dropBankSettled` +названо), мёртвая привязка `_ = terminologyCallsAfterFirst` заменена на живое утверждение о вызовах. + +⚠ **Что контролёр оставил НЕПРОВЕРЕННЫМ, а я проверил исполнением:** +- «влияет ли на кого-нибудь `res.Gendered`, который считается ДО слияния базисных родов» — **дефекта нет, и + это ЗАМЕР, а не рассуждение:** `res.Gendered = len(gendered)` стоит на `terminologist.go:552`, слияние — + на `:826`, то есть счётчик меряет ровно то, что обещает его докблок («сколько кандидатов получили род ОТ + КЛАССИФИКАТОРА»), и базисные роды в него не попадают намеренно — тот же принцип, что у `Reclassified`. +- моё же утверждение «между двумя чтениями банка глоссарий никто не пишет» — **пере-снято прибором:** + единственный не-тестовый вызывающий `ReplaceBank` — `backend/internal/pipeline/seeding.go:42`=`if err := r.Store.ReplaceBank(r.Book.BookID, in.entries, in.voices, in.pairs)`, + то есть `seedGlossary`, и в промежутке он не бежит. + +⚠ **Что контролёр НЕ смог проверить, и я это НЕ закрываю молчанием:** полную батарею с `-race` и полную +мутационную кампанию он не гонял (дорого); три его посадки прогнаны по двум пакетам, а не по модулю. Обе +дыры закрыты МОИМИ прогонами, числа в §8. + +##### 4в. Круг ПРИЁМКИ оркестратора — 6 находок, все приняты и починены + +Приёмка №23 подняла две линзы и посадки. Каждую находку я пере-снял своим прибором, прежде чем принять; +ни одна не отвергнута, и одна оказалась сильнее, чем её подали. + +| находка | класс | что сделано | чем предъявлено | +|---|---|---|---| +| **F1. Отпечаток описывает вход роли и молчит о том, КТО отвечает.** Производителя в нём нет, а денежный `RequestHash` его хеширует ⇒ до пака правка промта банк-роли давала промах чекпойнта и книга пере-покупала банк у НОВОГО производителя; после пака решённая строка не спрашивается никогда, и улучшение промта доезжает только до нерешённого хвоста — **навсегда** | мажор; **тихая потеря КАЧЕСТВА**, не денег: улучшение промта банк-роли есть прямой рычаг против translationese, цель №1 канона | производитель входит в отпечаток: `bankRoleProducer()` — модели обеих банк-ролей, общий уровень усилия и **SHA256 обоих пар-промтов**. ⚠ Снапшот НЕ берётся: он сворачивает банк, и отпечаток двигался бы на каждой строке | `TestTheFingerprintNamesWhoWouldAnswer` (четыре оси + контроль «тот же производитель — тот же отпечаток») · `TestTheProducerIdentityIsResolvedInOnePlace` · две записи каталога | +| **F2. «Чьё это слово» спрошено ВТОРЫМ написанием.** У движка есть одно определение — `membank.IsEngineUnsigned` — а базис спрашивал голое `Status == "approved"` в двух местах и поля `Source` не читал ни разу | мажор; ровно тот класс, который движок запрещает у соседа. Популяция законна: сид-терм ВЛАДЕЛЬЦА со статусом `draft` загрузчик допускает и даже ТРЕБУЕТ у него передачу | `membank.IsEngineUnsigned` в обеих точках; отдельный класс `owners-unsigned-row` — «ты подписал» и «ты написал рукой и не подписал» разные фразы владельцу; экземптирован из блокировки юнита | `TestAnOwnersUNSIGNEDRowIsNotTheEnginesMemoryEither` с контролем на строке ДВИЖКА того же статуса · запись каталога | +| **D1. Смена ширины улик докладывалась ЧУЖОЙ причиной.** Ширина жила только внутри хеша улик ⇒ её смена читалась как `evidence-moved`, «источник вокруг термина изменился» | средний, но про доверие к сообщению: реакции владельца на две причины ПРОТИВОПОЛОЖНЫ — одна «ничего не делать», другая «кто-то повернул ручку» | эффективная ширина входит в хранимую ФОРМУ (`basisShape`), и сообщение печатает обе формы | `TestAWidthChangeReportsItsOwnCauseAndNotTheSources` · запись каталога | +| **D2. У стоп-границы не было стража.** Замер приёмки с контролем: снятие записи на `run-finished` даёт `FAIL`, снятие на СТОП-границе оставляет пакет `ok` | мажор по цене: стоп возвращается ЗНАЧЕНИЕМ-ОШИБКОЙ, до `run-finished` такой прогон не доходит ⇒ резюм после подписи пере-купил бы ВЕСЬ проход | пин на стоп-границу, с утверждением ПОРЯДКА (базис до памяти флажка) и контролем «память флажка не пуста» | `TestTheSignatureStopWritesTheBasisToo` · запись каталога | +| **D3. Базис служил ответ, не сверяя его с текущей строкой банка** | средний; **популяция НАЗВАНА, а не заявлена** — на прогоне-писателе они совпадают по построению, достижимое расхождение это правка файла авто-банка рукой (онтология числит его ИСТОЧНИКОМ) | условие предиката в две строки, свой класс `bank-disagrees-with-the-memory`; сравнение под тем же фолдом целевых форм, что и голосование, — иначе движок покупал бы термин заново из-за регистра | `TestABankRowThatDisagreesWithTheMemoryIsReAsked` (+ пин на фолд) · запись каталога | +| **D5. ЧЕТВЁРТАЯ лгущая фраза, и она была ЗАКРЕПЛЕНА ПИНОМ.** «Роль не спрашивали ни о чём, потому что банк уже отдаёт всех кандидатов» — для книги с базисом ложны обе половины | средний; и правка требовала обслуживания пина, то есть объявления, а не тихого редактирования | фраза различает ДВЕ причины и печатает их числа раздельно; пин обслужен и расширен до трёх случаев, включая сочетание обеих | `TestTheSigningScreenSaysHowCompleteTheBankIs` · запись каталога | + +⛔ **И побочное от F2, которое я считаю находкой круга, а не издержкой починки:** фикс обвалил **пять моих +собственных пинов**, потому что их фикстуры строили «решение движка» БЕЗ поля `Source` — то есть строку, +которой в продакшне не бывает. Они были зелёными, потому что держали неверную посылку. Приведены к +продакшн-форме (`Source: "mined"`). + +⛔ **ВТОРОЙ ЗАХОД ПРИЁМКИ — ДВЕ НАХОДКИ, И ОБЕ ВНУТРИ ГРАНИЦЫ, КОТОРУЮ Я САМ ЖЕ И ПРОВЁЛ.** + +| находка | класс | что сделано | чем предъявлено | +|---|---|---|---| +| **Производитель докладывался ЧУЖОЙ причиной.** Я положил его ВНУТРЬ хеша улик ⇒ смена промта или модели давала вердикт `evidence-moved`, «источник вокруг термина изменился», — на КАЖДОЙ строке, о книге, которой никто не касался | мажор; **тот же класс, что я за час до этого починил у ширины, повторённый мной же**. И пин не ловил: он утверждал, что хеш ДВИНУЛСЯ, и не спрашивал, каким классом это доложено — зелен и пуст ровно там, где предмет | производитель — часть ПРАВИЛА, а не улика ⇒ переехал в хранимую ФОРМУ; три отдельных класса (`producer-changed` · `evidence-width-changed` · `fingerprint-shape-changed`), потому что реакции владельца на них разные: кто-то правил промт, кто-то повернул пар-данное, кто-то бампнул форму движка | `TestAProducerChangeReportsItsOwnCause` — утверждает КЛАСС, а не движение · запись каталога перенаведена | +| **В отпечатке не было БРИФА, а роль его читает.** Идентичность бралась с SHA ШАБЛОНА, тогда как пар-промт рендерит `{{title}}`, `{{audience}}`, `{{honorifics}}`, `{{transcription}}`, `{{venuti}}` ⇒ смена `honorifics: keep→adapt` пере-покупает обе волны книги через `BriefHash`, а базис продолжал бы подавать передачи, решённые под СТАРЫМ законом, в волны, купленные под НОВЫМ | мажор; ни улика, ни производитель этого не видели | идентичность берёт **отрендеренный системный промт** каждой роли. ⭐ Это пар-агностично ПО ФОРМЕ, а не перечислением полей в Go: что пара решила читать, входит само — прямой ответ на ревью-вопрос канона | `TestTheProducerIdentityIsResolvedInOnePlace` (бриф · модель · классификатор · нерендерящийся промт ≠ отсутствующая роль) · запись каталога | + +⚠ **И третье, что всплыло при починке и чего никто не называл:** запись с уехавшей формой я СБРАСЫВАЛ, а +сброшенная запись читается предикатом как `new` — «эту поверхность никогда не решали». То есть сводная +строка называла бы причину верно ОДИН раз, а каждая строка — неверно, и обе жили бы в одном прогоне. +Запись теперь хранится вместе со своей формой; цикл загрузки вынесен в чистую функцию **ровно потому, что +иначе это правило нельзя спросить посадкой** — внутри прохода ему нужны хранилище, книга и раннер, а +денежное правило, достижимое только сквозным прогоном, — это правило, в которое никто не сажает мутацию. +⇒ первая редакция записи под него **ВЫЖИЛА**, и это её и починило. + +⚠ **Два слепых пятна производителя названы там же, где перечисляется, чего в отпечатке НЕТ:** слаг модели +не есть модель (вендор двигает веса за тем же именем, и хешировать тут нечего), и пустой `reasoning` +означает «дефолт вендора», который уже двигался; боевые конвейеры усилие пинят явно. + +⛔ **МОЯ ПРОЦЕССНАЯ ОШИБКА ЭТОГО КРУГА, и она стоила приёмке часа.** Получив находки, я начал править дерево, +НЕ ОБЪЯВИВ окна, — и приёмка в этот момент по нему мерила: её кампания на 307 записях считала час на корне, +снятом до моих правок, и её числа пошли в мусор. Норма, которую это купило: **сдавший пак не трогает дерево, +пока идёт приёмка, даже чиня её собственные находки — сначала объявляет окно, потом правит.** Законность +правки не в том, что она правильная, а в том, что она ОБЪЯВЛЕНА: приёмка судит конкретное дерево, и дерево, +движущееся под ней, превращает её отчёт в описание состояния, которого нет. + +##### 5. Обслуженные пины — каждый назван, с тем, куда уехала гарантия + +| пин | что изменилось в поведении | куда уехала гарантия | +|---|---|---| +| `TestAResumeFindsItsCheckpointsAfterTheFilter` | резюм ТОЙ ЖЕ покупки стал «$0 со второго» | два прогона → три: run2 ОБЯЗАН объявить разовую цену И дойти до провайдера, run3 обязан быть $0 и не звать его. Пин сильнее прежнего: вторую ось прежняя форма не выражала | +| `TestTheRunTotalIsThisRunsSpendIncludingTheClassifier` | — | **разделён на два.** Одной фикстуре нужен бюджет, РЕЖУЩИЙ батч, другой — с ЗАПАСОМ; с базисом требования стали арифметически несовместимы (перебор 0.0037 / 0.005 / 0.006 / 0.008). Оба утверждения живы | +| `TestAutoWireIsDeterministicAndDoesNotMoveTheDraftWave` | тот же класс | добавлен прогон переупаковки, и его ПОКУПКА утверждается | +| `TestRowsWrittenBeforeTheThinkingColumnReadAsUnanswered` | голова схемы 18 → 19 | выражал «предыдущую версию» через `len(migrations)-1` — верно лишь пока та миграция БЫЛА головой; переписан на поиск миграции, добавляющей колонку | +| `migrate_cli_test.go` | то же | 18 → 19, список колонок головы ПУСТ: v19 создаёт таблицу | +| `TestEveryDecidingFieldSurvivesTheProjection` | выросло поле проекции | «каждое поле непусто» перенесено с ОДНОЙ строки на НАБОР: `Invented` и `SettledEarlier` не могут быть истинны одновременно | +| голден `operator-messages.txt` | 6 новых сообщений + пере-формулировка ряда 448 | 144 → 149 строк. Пины сообщения держатся на КЛЮЧЕ `reconsolidated`, а не на прозе | + +##### 6. ДВА ОТКАЗА, оба с замером + +⛔ **Ряд 447 — НЕ ДЕЛАЮ.** Смена продуктового поведения, а не починка: фильтр платит за банкованные +поверхности НАРОЧНО, потому что ответ роли читают две проверки спора, и это метки на подписном листе. +Замер популяции: подписанных строк по **2** из 69 и 66 ⇒ выгода ограничена **3 %** прохода, ценой был бы +разбор споров у населения, ради которого фильтр двух-условен. **Что сделано вместо** — отделено следствие, +которое менять безопасно: подписанная строка больше не ДЕРЖИТ семью (покупается по-прежнему). + +⛔ **Сторож растущей книги — НЕ ДЕЛАЮ, и это ответ владельцу ЧИСЛОМ.** Посылка «исходник приходит целиком» +— открытый вопрос владельцу; сторож «хеш разошёлся — кричим» у растущей книги обнулял бы базис на каждом +выпуске, то есть ответил бы за владельца молча. Вместо сторожа — поведение по построению и числа §3. +**Что механизм делает при разошедшемся хеше: ничего особенного — он не сравнивает хеш исходника вовсе.** +Отпечаток пер-кандидатный, поэтому «подменён» и «дописан» различаются автоматически. + +##### 7. Рефакторинг + +**Отдельного рефакторинга не потребовалось**, и один начатый я **ОТКАТИЛА** — см. §4 п.5: сведение трёх +копий пере-ранжирования в хелпер увело предмет чужого денежного пина из-под его посадки. Единственное +движение существующего кода, которое осталось: чтение банка (`r.glossaryRows()`) поднято выше по функции, +чтобы предикат и проверки спора читали ОДИН банк одного прогона; второе чтение в `dropBankSettled` +пред-существует и НАЗВАНО в комментарии, а не замолчано. + +##### 8. Приборы — числа и команды + +- **Батарея зоны**, `make battery`: **MAKE_EXIT=0**, линтер `0 issues.`, целей отработало **8 команд** + (build · vet ×4 · lint · test), `go list` **24** = вердиктов **24**, `comm -23` пуст И `comm -13` пуст, + FAIL **0**. ⚠ Линтер дважды ловил у меня то, что `go test` пропускал (`ineffassign`, затем `staticcheck`): + `lint` стоит ДО `test`, и «все тесты зелёные» здесь ничего не значит. +- **Мутации пака, прицельно** (`tmmutate -id`, 27 записей включая пере-наведённую чужую): **27/27 RED, + 0 неожиданных, 0 протухших**. +- **Полные прогоны каталога — их было ПЯТЬ, и я называю все, включая два несостоявшихся.** + 1. **Первый, 296 записей: 295 RED · 1 SURVIVED · 0 UNKNOWN · 0 ROTTED.** Выживший — + `BANKMONEY-the-run-total-reports-the-contours-cumulative-spend`, причина в §4 п.4, починен. + 2. **Второй — Я ЕГО УБИЛА** (адверсариальный круг переписал предмет под ним). + 3. **Третий, 307 записей: 307 RED · 0 SURVIVED · 0 UNKNOWN · 0 ROTTED.** Верен для дерева ДО круга приёмки. + 4. **Четвёртый — ОБОРВАЛСЯ на 209 вердиктах из 315.** Я послала ему `kill` (круг приёмки переписал + предмет под ним), и в то же окно харнесс сообщил, что остановил его по нехватке памяти. **Какая из + двух причин сработала первой, я предъявить не могу**, и пишу дизъюнкцию вместо удобной определённости: + несущее различие тут «оборван ≠ прошёл частично», и оно сохраняется при любой из причин. + ⚠ Что при этом ТОЧНО не было причиной — потолок cgroup: `/proc/self/cgroup` даёт `0::/`, и файла + `memory.max` у него НЕТ вовсе. То есть канонический класс «убил потолок собственного юнита» здесь ни + при чём, и первая моя версия этой строки называла бы неверную причину дважды. + 5. **Пятый, финальный, на дереве, которое я сдаю: 315 записей → 315 RED · 0 SURVIVED · 0 UNKNOWN · + 0 ROTTED · 0 NOTHING, `TMMUTATE_EXIT=0`, `anchors swept: 0 of 526 entr(ies) rotten`.** + Полнота сверена не хвостом лога: вердиктов **315** при **315** записях с флагом `battery` в каталоге + ТОГО ЖЕ прогона. **Выживших нет. Неизмеренных нет.** + + ⛔ **Оба убитых в число идут НУЛЁМ, а не своей частичной выдачей**, и гашение шло по СВОИМ PID, по одному, + после `ps` глазами: `go test` и `tmmutate` — имена, общие для всех зон. **Прерванный прогон не есть + прогон**, и разница между «убит» и «не запускался» для акта нулевая — а вот между «убит» и «прошёл + частично» огромная, поэтому названо. +- **Каталог:** 492 → **526** записей, в гейте 281 → **315**. Моих — **34**, все помечены `battery`. +- ⛔ **ОДИН из моих новых тестов — НЕ ПИН, А ПРИБОР, и без руки он не стережёт ничего.** + `backend/internal/pipeline/bankbasis_m1_probe_test.go:57`=`func TestProbeBankBasisM1` гейчен переменной + `TM_BASIS_M1` (`backend/internal/pipeline/bankbasis_m1_probe_test.go:60`=`instrument: set TM_BASIS_M1`) и + не ставится НИ ОДНОЙ целью Makefile ⇒ в батарее он + СКИПАЕТСЯ, и его зелень не значит ничего. ⇒ по числу новых тестов пинов у пака на один меньше, чем + кажется, и следующая смена обязана прочесть это здесь, а не в докблоке файла: **в коде названо, в отчёте + нет — значит для следующей смены не названо.** ⚠ Две другие env-гейченные пробы в этом пакете + (`TestProbeBankBatchOrdinalShift`, `TestCorpusBankKeyConflicts`) **пред-существуют** и паку не + принадлежат — провенанс снят диффом, а не грепом файла. +- ⭐ **И вопрос, который за этим стоит на самом деле, задан и закрыт числом: записей каталога, чей ЛОВЕЦ + env-гейчен, — 0 из 34.** Прибор в неработающем наборе — полбеды; беда — ПОСАДКА, чей ловец молчит: она + даёт выжившую или «nothing ran», и обе читаются как находка о предмете. Контроль печатается рядом с + нулём: env-гейченных тестов прибор нашёл в дереве **12** (в их числе `TestCheckerLabelsBaseline` и + `TestCorpusBankKeyConflicts`) — то есть вопрос задан существующему предмету. + +##### 9. Что НЕ удалось и где мой прибор СЛЕП + +1. ⛔ **M1 не судит КАЧЕСТВО.** Отвечает «сколько строк не пере-спрошено» и ни одним числом не говорит, + хороши ли сохранённые передачи. Не чинил: нужен платный судья, пак объявлен $0. Закрывается полигоном. +2. ⛔ **Замер на книге из ТРЁХ глав и одной пары.** Юниты мелкие (крупнейший 4), поэтому цена правила + «семья целиком» измерена там, где ей негде развернуться. На длинной книге число может быть другим. +3. ⚠ **Стык чанков — БЫЛО слепой зоной, теперь ИЗМЕРЕНО** (§3): 6–12 % при двукратной смене кроя. Не чиню: + альтернатива — вторая копия определения «нормализованный исходник», и одно определение дороже. +4. ⛔ **`basis_width` не заполнен НИ ОДНОЙ парой** (контроль: `terminology.txt` — 0 файлов при 16 + прочитанных). Пар-данность построена и ТЕПЕРЬ запинена, но живьём не исполняется ничем. +5. ⚠ **Смена `basisFingerprintVersion` обнуляет базис КАЖДОЙ книги разом.** Названо в комментарии и + объявляется сообщением; механизма «пере-считать отпечатки без покупки» нет, хотя он возможен ($0). + Кандидат в ряд бэклога. +6. ⛔ **Поле `settled_earlier` — ПОСТРОЕНА ОДНА ПОЛОВИНА ИЗ ДВУХ.** Движковая: поле публикуется в + `bank.json` — в сводке (число) и построчно (флаг). **Платформенная НЕ построена, наружу по контракту + поле не отдаётся.** Платформа собирает секцию консолидации ПОИМЁННЫМ перечислением в ШЕСТИ местах, + включая колонку Postgres и её миграцию ⇒ аддитивное поле движка туда не доезжает само. + **Контроль:** `settled_earlier` в `platform/` — **0** файлов, соседнее `never_asked` — **8**, прибор + прочёл **215** `.go`-файлов зоны. Носитель обязательства — строка трекера оркестратора. +7. ⚠ **Онтологию правил пак, ратифицирует НЕ пак.** Пятая роль и вторая петля вписаны по прямому указанию + эрраты 17.09-д; страница ратифицирована `D39.158`, и её новая строка живёт под чужой ратификацией, пока + оркестратор не закроет это нотой лендинга. +8. ⚠ **Три посадки адверсариального контролёра прогнаны им по ДВУМ пакетам, а не по модулю** — то есть его + «выжила» означало «её не ловит ни один тест этих двух». Дыра закрыта моими прогонами (§8), но сам его + вывод был у́же, чем звучал, и я это называю, а не наследую. + +##### 10. Завершённость + +- Батарея зоны пере-снята ПОСЛЕДНЕЙ, после всех правок: `MAKE_EXIT=0`, линтер `0 issues.`, восемь команд + гейта, `go list` 24 = вердиктов 24, `comm` пуст в обе стороны, FAIL 0. Контроль: файлов зоны, изменённых + ПОЗЖЕ этого прогона, — **ноль** (`find -newer` по логу батареи). +- Числа M1 пере-сняты после последней правки; промежуточные в отчёте не цитируются. +- Дерево держит **33 пути**: **31** в зоне `backend/` (`git status --porcelain -- backend | wc -l`) плюс + `docs/architecture/18-bank-ontology.md` и эта секция журнала. ⚠ Прежняя редакция называла здесь только + число ЗОНЫ, и внимательный читатель прочёл его как ИТОГ: **число, которое надо складывать в уме, в + секции завершённости плохое**, поэтому здесь стоят оба. +- ⛔ **Про чужое — со знаменателем, потому что прежняя форма была ВАКУУМНОЙ.** Стояло «чужих путей в + индексе нет» — истинно и пусто: в индексе **0** путей ВООБЩЕ, включая мои, то есть утверждение о чужом + держалось на пустоте. Честная форма: **индекс пуст (0 staged)**, а в РАБОЧЕМ дереве один чужой путь — + `platform/docs/DEFECT_REGISTER.md` (1 строка, ячейка платформенной зоны, закрывшая `PD-441`). Он не мой, + я его не трогала, и он едет со своим лендингом, а не с моим. Не коммичу. + +**Работа завершена, править не планирую.** + + #### ЗАПИСКА-ПЛАН пака «РЕШЁННОЕ НЕ ПЕРЕ-СПРАШИВАЕТСЯ» (17.09, сессия `textmachine-main-57`). До первой правки кода, по §7 промта **Деньги: $0.** Платных вызовов моделей пак не делает. Всё ниже снято чтением дерева и купленного сырья @@ -265,7 +615,7 @@ Консилиум писал букву «файл рядом с базой» (`bank-basis.yaml`). **Беру таблицу**, и довод не про вкус: 1. **Роль носителя в онтологии.** Файл рядом с базой (`auto-bank`) принадлежит роли **ИСТОЧНИКИ** — тому, из - чего пересобирается вид (`docs/architecture/18-bank-ontology.md:15`=`**ИСТОЧНИКИ** — то, из чего банк собирается`). + чего пересобирается вид (`docs/architecture/18-bank-ontology.md:21`=`**ИСТОЧНИКИ** — то, из чего банк собирается`). Базис источником не является: из него не собирается ни одна строка банка, его читает предикат. Класть память решений в каталог источников значит завести источник, который ничего не порождает, — а онтология судит носитель с несовпавшей ролью так же строго, как проекцию без читателя. @@ -331,7 +681,7 @@ langpacks — **0 файлов** при **16** прочитанных прибо то есть до `run-finished` такой прогон не доходит и резюм после подписи оплатил бы весь проход. **Порядок на границе стопа:** карта → таблица стопа → проекция банка → **базис** → память флажка. -Довод берётся у самого кода: `backend/internal/pipeline/mining.go:271`=`a crash between the two costs one benign re-stop` — +Довод берётся у самого кода: `backend/internal/pipeline/mining.go:278`=`a crash between the two costs one benign re-stop` — последней пишется запись, чья потеря ДЕШЕВЛЕ. Потеря памяти флажка стоит одного доброкачественного стопа; потеря базиса — пере-покупки банк-ролей из ПОЖИЗНЕННОГО потолка (ряд **356**). ⇒ базис раньше. ⛔ Писать базис сразу после платного прохода, ДО развилки, нельзя: базис на краш-резюме сожмёт состав батчей, @@ -346,16 +696,16 @@ langpacks — **0 файлов** при **16** прочитанных прибо | читатель | адрес | что получает | |---|---|---| -| `attachConsolidatedDst` → режим эмиссии | `backend/internal/pipeline/terminologist.go:1291`=`Terms the role did not answer are left untouched` | передачу ⇒ `draft` вместо отката к догадке куска | -| `attachClassifiedType` / `attachClassifiedGender` | `backend/internal/pipeline/terminologist.go:1306`=`attachClassifiedGender stamps` | тип и род из базиса | -| `consolidatedRows` → `ConsolidationKeyConflicts` | `backend/internal/pipeline/terminologist.go:646`=`membank.ConsolidationKeyConflicts(consolidatedRows(cands, out), bank)` | судится, см. решение ниже | -| `CanonConflicts` | `backend/internal/pipeline/terminologist.go:624`=`terminology.CanonConflicts(cands, out, canon)` | судится, см. решение ниже | +| `attachConsolidatedDst` → режим эмиссии | `backend/internal/pipeline/terminologist.go:1415`=`Terms the role did not answer are left untouched` | передачу ⇒ `draft` вместо отката к догадке куска | +| `attachClassifiedType` / `attachClassifiedGender` | `backend/internal/pipeline/terminologist.go:1430`=`attachClassifiedGender stamps` | тип и род из базиса | +| `consolidatedRows` → `ConsolidationKeyConflicts` | `backend/internal/pipeline/terminologist.go:747`=`membank.ConsolidationKeyConflicts(consolidatedRows(cands, out), bank)` | судится, см. решение ниже | +| `CanonConflicts` | `backend/internal/pipeline/terminologist.go:725`=`terminology.CanonConflicts(cands, out, canon)` | судится, см. решение ниже | | `ConsolidationConflicts` (§G2, свои против своих) | рядом, тот же цикл | судится | | `labelRows` → `TypeLabelMismatches` | там же | судится | -| счётчики `Consolidated`/`Declined`/`Unanswered` | `backend/internal/pipeline/terminologist.go:618`=`res.Consolidated++` | ⛔ НЕ вливать базисные в общий набор до цикла счёта: поле сменит смысл без единой строки об этом | -| таблица стопа и её сайдкар | `backend/internal/pipeline/mining.go:502`=`row.Invented = dst != "" && !proposedByDrafts(dst, c.Variants)` | отдельное состояние, см. ниже | -| очередь спорных | `backend/internal/pipeline/stopcontest.go:75`=`if r.SettledByBank` | ⛔ решается ОТДЕЛЬНО, не наследуется по совпадению имени | -| проекция банка наружу | `backend/internal/pipeline/bankexport.go:118`=`NeverAsked: t.BankSettled` и `backend/internal/pipeline/bankexport.go:251`=`Contradicts: row.Contradicts, BankHolds: row.BankHolds` | АДДИТИВНОЕ поле, см. §5 | +| счётчики `Consolidated`/`Declined`/`Unanswered` | `backend/internal/pipeline/terminologist.go:719`=`res.Consolidated++` | ⛔ НЕ вливать базисные в общий набор до цикла счёта: поле сменит смысл без единой строки об этом | +| таблица стопа и её сайдкар | ⚠ ИСТОРИЧЕСКОЕ (до этого пака формула была `row.Invented = dst != "" && !proposedByDrafts(dst, c.Variants)`, и адрес намеренно НЕ в якорной форме: цель не уехала, а ИЗМЕНИЛАСЬ — её починил этот пак, и подставить найденный в цели токен значило бы подогнать якорь под то, что там оказалось). Живая строка — `backend/internal/pipeline/mining.go:525`=`row.Invented = dst != "" && !row.SettledByBasis` | отдельное состояние, см. ниже | +| очередь спорных | `backend/internal/pipeline/stopcontest.go:83`=`if r.SettledByBank` | ⛔ решается ОТДЕЛЬНО, не наследуется по совпадению имени | +| проекция банка наружу | `backend/internal/pipeline/bankexport.go:128`=`NeverAsked: t.BankSettled` и `backend/internal/pipeline/bankexport.go:269`=`Contradicts: row.Contradicts, BankHolds: row.BankHolds` | АДДИТИВНОЕ поле, см. §5 | ##### 4а. РЕШЕНИЕ по двум проверкам спора (развилка §4.2 промта): **ДА, базисный ответ ими судится** @@ -389,14 +739,14 @@ langpacks — **0 файлов** при **16** прочитанных прибо `never_asked` сегодня равно числу снятых банком и значит «сид держит поверхность и все черновики согласны». Базисные строки туда класть нельзя без смены смысла ⇒ **аддитивное поле проекции** (минор контракта; пинг платформе даёт оркестратор). Три фразы, которые для базисной строки лгут ДОСЛОВНО обеими половинами и потому -правятся вместе с полем: `backend/cmd/tmctl/render.go:282`=`the bank already renders those surfaces and every` · -`backend/cmd/tmctl/render.go:328`=`NOT ASKED: the bank already renders this surface` · -`backend/internal/pipeline/mining.go:579`=`nothing to decide`. +правятся вместе с полем: `backend/cmd/tmctl/render.go:299`=`the bank already renders those surfaces and every` · +`backend/cmd/tmctl/render.go:352`=`NOT ASKED: the bank already renders this surface` · +`backend/internal/pipeline/mining.go:607`=`NOT ASKED(the bank already renders this surface and every draft agreed`. ##### 6. Юниты (§4.5) — ОТДЕЛЬНЫЙ ПРОХОД, батчер не трогаю Семьи и серии сегодня детектируются НАД `paid`, то есть ПОСЛЕ фильтра -(`backend/internal/pipeline/terminologist.go:486`=`terminology.DetectFamilies(paid, fp)`), и комментарий выше объясняет причину: детектировать над полным +(`backend/internal/pipeline/terminologist.go:574`=`terminology.DetectFamilies(paid, fp)`), и комментарий выше объясняет причину: детектировать над полным набором значит рассогласовать юниты с батчами, из них построенными. **Но это довод про БАТЧИ, а не про предикат.** Если считать юнит над `paid`, юнит будет определён тем самым фильтром, который он питает, — круг. ⇒ юнит для предиката считается **отдельным чистым проходом над ВСЕМИ кандидатами**, батчер остаётся @@ -427,7 +777,7 @@ langpacks — **0 файлов** при **16** прочитанных прибо - **Ряд 490** (страж разрыва окон глав) — $0, беру, образец `backend/internal/membank/memvoice.go:271`=`func VoiceWindowGaps`; у образца беру и ГАРАНТИЮ: намеренный разрыв законен ⇒ исход громкая строка, а не отказ загрузки. - **Ряд 448** — пере-формулировка обязана обновить И голден каталога операторских сообщений - (`backend/internal/pipeline/testdata/operator-messages.txt:136`=`terminology: this book had already paid`), и это + (`backend/internal/pipeline/testdata/operator-messages.txt:141`=`terminology: this book had already paid`), и это обслуживание заказанной смены поведения (`D39.183`), а не подгонка под зелень. Объявляю заранее. - **Ряд 487** пак НЕ чинит, но посылку «решено ⇒ `draft`» пиню: без пина завтрашняя починка скачком двинет набор решённых, то есть деньги. diff --git a/docs/README.md b/docs/README.md index b16b5946..fbc5320a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -24,8 +24,9 @@ - **Активные хендофф-промты — какой файл ТВОЙ** (состав обновляется при каждом лендинге, D39.80; хроника, причины и статусы РАБОТ — CURRENT-STATE и D-лог): | Роль | Активный промт | Статус | |---|---|---| +| **Бэкенд · АНГЛИЙСКАЯ ПАРА en→ru** | [BACKEND_ENGLISH_PAIR_SESSION_PROMPT.md](BACKEND_ENGLISH_PAIR_SESSION_PROMPT.md) | **ВЫДАН 17.09** сессии `textmachine-main-c5` (холодная по всем трём носителям: блока в канале нет, упоминаний в живых доках нет, в D-логе ноль). ⭐ **Центр пака — СЛОЙ ДАННЫХ английского языка** (слово владельца 17.09: «код может быть и да, но вот данные надо написать… уникально описать английский язык… от этого качество перевода зависит»); китайский берётся как образец ФОРМЫ вопросов, ответы пишутся английскими категориями. Две стены (`EXIT 10`): нет промт-пакета пары и гейт терминолога при пустом паке. Тихое: порог эха `0.15` унаследован от китайского бенчмарка и на латинице ЭСКАЛИРУЕТ ложно; второй детектор латиницы работает без гейта и требует аллоу-листа, а не правки порога. Материал — Кристофф «Империя рассвета», мера по ТОКЕНАМ (решение владельца). Fable 5 разрешён исполнителю ОДИН, под верификацию данных. Два рубежа пройдены: механическая сверка 13 блоков (27 адресов, битых 0) и субагент-опровергатель — **15 находок, 9 приняты, 6 уточнены моими числами**, включая ЧЕТЫРЕ моих ошибки популяции. $0 по умолчанию | | Платформа · ПРОГОН НЕ ВРЁТ О СЕБЕ | активного НЕТ | пак ОТРАБОТАН и **ПРИНЯТ 17.09** — акт **D39.265** (32 пути, $0, контрактный минор **0.17.0**); промт в [archive/prompts/](archive/prompts/PLATFORM_RUN_TELLS_THE_TRUTH_SESSION_PROMPT.md) с баннером-исходом. Ряды **398** · **399** · **400** · **486** закрыты работой, **394** и **396** — ПЕРЕ-РЕШЕНИЕМ (четвёртое значение в клиентский словарь не идёт: «мы сами перестали перезапускать» — другая ось, чем «стоит ли повторять», и границу между осями стережёт новый гейт на три носителя), **416** — платформенной половиной. Кампания пере-снята приёмкой: 26 записей · поймано 25 · выжила 1, объявленная ДО прогона · неизмеренных 0. ⛔ Гейт зоны красен на экземпляре ряда **484** (фикстурный бюджет записи под нагрузкой; оба упавших теста живут в чистом `HEAD`) — названо границей, а не зеленью. ⚠ Две ошибки приёмки названы в акте: оркестратор взял себе правку канона (откачена) и неточно сформулировал §4.1 промта. Живое — ряды **416** (движковая половина) · **484** · **493** · **494** | - | **Бэкенд · РЕШЁННОЕ НЕ ПЕРЕ-СПРАШИВАЕТСЯ** | [BACKEND_SETTLED_STAYS_SETTLED_SESSION_PROMPT.md](BACKEND_SETTLED_STAYS_SETTLED_SESSION_PROMPT.md) | **ВЫДАН 17.09** сессии `textmachine-main-57` (свежая: паков не брала, контекст пуст — проверено опросом, а не списком). ⚠ Свежих нашлось ДВЕ; вторая (`textmachine-main-78`) оставлена нетронутой, ей сказано не читать промт и не занимать зону — один промт на зону. Предмет: движок на каждой покупке заново платит банк-ролям за решённые термины — 12 из 69 и 14 из 66 смен передачи при неизменной улике у 25 из 26 строк; потолки ролей ПОЖИЗНЕННЫЕ. Строит базис решённого (ряд **130**) и стража разрыва окон (ряд **490**). Два рубежа пройдены: механическая сверка 13 блоков (27 якорей, все живы) и субагент-опровергатель — **12 находок, 9 денежных, все внесены**, включая мою ложь «текста в коде нет» о живой строке и материал замера, из которого предмет не строился. $0 | + | Бэкенд · РЕШЁННОЕ НЕ ПЕРЕ-СПРАШИВАЕТСЯ | активного НЕТ | пак ОТРАБОТАН и **ПРИНЯТ 17.09** — акт **`D39.266`** (`d25e418`, 32 пути, $0); промт в [archive/prompts/](archive/prompts/BACKEND_SETTLED_STAYS_SETTLED_SESSION_PROMPT.md) с баннером-исходом. Решённая строка переживает покупку: носитель — таблица `bank_basis`, миграция v19, аддитивная. Ряд **490** закрыт по трём условиям, **130** получил ТРЕТИЙ исход (замысел достигнут другим механизмом, стоп-решение за владельцем), два отказа с замером, заведён **496**. Числа приёмки оркестратора: кампания **315/315 поймано, выживших 0, неизмеренных 0**; M1 — **67 из 69** и **64 из 66** обслужено из памяти. ⛔ Приёмка нашла две дыры ОДНОГО класса — не неверное число, а отсутствующее утверждение — и купила норму «сверять перечень заказа по СПИСКУ ЗАКАЗЧИКА». Выдавался 17.09 сессии `textmachine-main-57` (свежая: паков не брала, контекст пуст — проверено опросом, а не списком). ⚠ Свежих нашлось ДВЕ; вторая (`textmachine-main-78`) оставлена нетронутой, ей сказано не читать промт и не занимать зону — один промт на зону. Предмет: движок на каждой покупке заново платит банк-ролям за решённые термины — 12 из 69 и 14 из 66 смен передачи при неизменной улике у 25 из 26 строк; потолки ролей ПОЖИЗНЕННЫЕ. Строит базис решённого (ряд **130**) и стража разрыва окон (ряд **490**). Два рубежа пройдены: механическая сверка 13 блоков (27 якорей, все живы) и субагент-опровергатель — **12 находок, 9 денежных, все внесены**, включая мою ложь «текста в коде нет» о живой строке и материал замера, из которого предмет не строился. $0 | | **Бэкенд · БАНК ЗА $0** | активного НЕТ | пак ОТРАБОТАН и **ПРИНЯТ 16.09 С НАЗВАННЫМ ОСТАТКОМ** — акт **`D39.257`**; промт в [archive/prompts/](archive/prompts/BACKEND_BANK_ZERO_LAYER_SESSION_PROMPT.md) с баннером-исходом. 29 путей, $0. ⭐ Посылка `D39.256` перестала быть посылкой: 25 из 26 смен при идентичном входе. ⛔ Мажоры — сдвинутые якоря (ряд 467) и арм по чужому знаменателю (ряд 462). ⚠ Остаток: полный прогон каталога мутаций (267) на момент акта не закончен. **Слот бэкенда СВОБОДЕН** | | **Бэкенд · КУПЛЕНО — ЗНАЧИТ ДОСТАВЛЕНО** | активного НЕТ | пак ОТРАБОТАН и **ПРИНЯТ 16.09 С НАЗВАННЫМ ОСТАТКОМ** — акт **`D39.255`**; промт в [archive/prompts/](archive/prompts/BACKEND_BOUGHT_MEANS_DELIVERED_SESSION_PROMPT.md) с баннером-исходом. Лендинг `af88680`, 29 путей, $0. Закрыты строки **291** и **379** (вторая — ЗАМЕРОМ: мутант 8/8 против 7/8 в ряду). ⛔ Пак пережил ПОТЕРЮ сессии: `textmachine-b1` построила почти всё и исчезла при переезде окружения, доводила `textmachine-main-b1` разделом ПЕРЕДАЧИ ред. 5. ⚠ Остаток — строки **375** · **232** · **453**–**456**; три опубликованных ключа качества сменили смысл (п.5 акта). **Слот бэкенда СВОБОДЕН** | | Сквозной · ХОЛОДНЫЙ ПРОГОН B | активного НЕТ | пак ОТРАБОТАН и **ПРИНЯТ 11.09** — акт **D39.252**; промт в [archive/prompts/](archive/prompts/COLD_RUN_B_SESSION_PROMPT.md) с баннером-исходом. Книга второй раз от двери до ФАЙЛА, факт **$0.396657**. ⭐ Две меры денежной дыры разошлись в РАЗНЫЕ стороны на одних данных; **85.7 % оплаченного выхода — размышление, а не текст**. ⛔ Прибор приоритета №1 солгал вердиктом по подписанному имени героя. Качество впервые судилось по ОРИГИНАЛУ рядом с переводом: 26 находок, 1 крит | diff --git a/docs/architecture/05-decisions-index.md b/docs/architecture/05-decisions-index.md index e909d5f5..3cd75b90 100644 --- a/docs/architecture/05-decisions-index.md +++ b/docs/architecture/05-decisions-index.md @@ -1,4 +1,4 @@ -# Реестр D-нот — карта актуальности v2 (D1–D39.265; титул — носитель головы, бампать при каждом аппенде) +# Реестр D-нот — карта актуальности v2 (D1–D39.266; титул — носитель головы, бампать при каждом аппенде) > ⚠ **Колонку «тело» `counts.py --check` НЕ сторожит по устройству:** он сверяет полноту НОМЕРОВ, а не > место тела, поэтому колонка держится дисциплиной лендинга. Не нашёл тело по колонке — иди в слайсы, @@ -324,3 +324,4 @@ | D39.263 | 17.09 | **ОСТАТОК КОНСИЛИУМНЫХ РАСХОЖДЕНИЙ ЗАКРЫТ.** Д-1+Д-2 одной нотой: производитель проактивного `gender=hidden` — ЧЕЛОВЕК через сид, детектора не вводить; роль, названная ДВУМЯ ратифицированными нотами, в движке отсутствует (замер: 0 хитов при контроле 188). Д-6+Д-17: условия `D39.76`, ряда 192, `D39.144` п.1, `D21` п.2 ПРИОСТАНОВЛЕНЫ, а не отменены — сужение области не есть отмена. ⛔ Д-3 ОТКЛОНЁН (второй отказ после Д-13): адрес указывал в несуществующий путь, а по верному ветка статуса не касается, инвариант `D39.42` §C2-7 держится. ⭐ Но проверка вскрыла другое — `status:auto` с непустым `dst`, состояние, которое четыре комментария движка объявляют невозможным: ряд **487** | ЖИВОЕ: ряды 444 · 487; правка строки языковых данных — зона бэкенда | жив | банк процесс | | D39.264 | 17.09 | **ПРИЁМКА ПАКА «ЛЕСТНИЦА ПОПЫТКИ ДЛЯ БАНК-РОЛЕЙ»** — 18 путей, $0. Петля повторной попытки вынесена в общий контур, банк-роли подключены к вердикту, который движок вычислял и ВЫБРАСЫВАЛ; ступени бюджетируются политикой фазы, где `nil` = одиночный выстрел по построению. Кампания на финальной редакции: `MUT_EXIT=0`, 281 из 281 RED, выживших и неизмеренных 0, каталог 492. ⛔ Два пункта заказа закрыты ОТКАЗОМ С ЗАМЕРОМ и оба приняты: хоп банк-ролей (болезнь лечится бюджетом, не другой моделью) и ключ батча (посылка ряда 478 опровергнута прибором в дереве). ⭐ Полный прогон каталога нашёл то, чего не увидел ни один более дешёвый прибор: рефактор МОЛЧА обездвижил чужой пин при совпадающем якоре. Приёмка дала четыре находки, все починены: асимметрия записи счётчиков · отсутствие посадки у единственной денежной ручки в бою · поимка по неверно названной причине · число, снятое в середине работы и не пере-снятое | ЖИВОЕ: ряды 481 · 484 · 487 · 488; форма гейта названа точно — `make battery` целиком не отработал, цели прогнаны по отдельности | жив | банк деньги процесс | | D39.265 | 17.09 | **ПРИЁМКА ПЛАТФОРМЕННОГО ПАКА «ПРОГОН НЕ ВРЁТ О СЕБЕ»** — 32 пути, $0, контрактный минор **0.17.0** (`Run.progress_lagging` и `Run.rebill_consent_micro_usd`). Закрыты работой ряды **398** · **399** · **400** · **486**, ПЕРЕ-РЕШЕНИЕМ — **394** (четвёртое значение в клиентский словарь не идёт: «мы сами перестали перезапускать» — другая ось, чем «стоит ли повторять», и границу стережёт гейт на три носителя) и **396** («оставить, с капом как условием»), половиной — **416**. Кампания пере-снята оркестратором: 26 записей · поймано 25 · выжила 1 (объявлена до прогона) · неизмеренных 0. ⛔ Гейт зоны красен на экземпляре ряда **484** (фикстурный бюджет записи под нагрузкой), оба теста живут в чистом `HEAD`. Находки приёмки: канон описывал происхождение денежного согласия у́же кода · всегда-посылаемый член вне `required` · харнесс читает пустой шаблон как выжившую. ⚠ Две мои ошибки: взял себе правку канона (откачена) и неточная посылка §4.1 промта | приёмка | `docs/archive/prompts/PLATFORM_RUN_TELLS_THE_TRUTH_SESSION_PROMPT.md` | +| D39.266 | 17.09 | **ПРИЁМКА БЭКЕНД-ПАКА «РЕШЁННОЕ НЕ ПЕРЕ-СПРАШИВАЕТСЯ»** — `d25e418`, 32 пути, $0. Решённая движком строка переживает покупку: носитель — таблица `bank_basis` (миграция v19, аддитивная, `memory_version` не двигает). РАТИФИЦИРОВАНЫ смена поведения (первый прогон после появления базиса платит ОДИН раз за переупаковку хвоста батчей: run1/run2 по `$0.001820`, run3/run4 по нулю) и пятая роль онтологии — ПАМЯТЬ РЕШЕНИЙ со второй петлёй защиты подписанного. Ряды: **490** закрыт по трём условиям (страж · живой путь · посадка), **130** получил ТРЕТИЙ исход — замысел достигнут другим механизмом, механизм ряда не построен намеренно, стоп-решение остаётся за владельцем, остаток сужен до двух предметов; **447** и сторож растущей книги — отказы с замером; заведён **496**. Числа приёмки сняты оркестратором: батарея `MAKE_EXIT=0` 24=24 при 11 названных скипах, пять корпусных тестов предъявлены исполнением, кампания **315/315 поймано, выживших 0, неизмеренных 0** с полнотой в обе стороны, M1 — **67 из 69** и **64 из 66** обслужено из памяти при верности реконструкции без расхождений. ⛔ Приёмка нашла в отчёте две дыры ОДНОГО класса — не неверное число, а отсутствующее утверждение (прибор, не названный прибором; заказанный ряд без исхода), и купила норму: **собственные проверки не находят отсутствующее, потому что знаменателем им служит свой же текст** ⇒ сверять перечень заказа по СПИСКУ ЗАКАЗЧИКА. ⚠ Шесть ошибок оркестратора названы в теле, включая два ложных ноля по `books/` от двух РАЗНЫХ приборов | приёмка | `docs/archive/prompts/BACKEND_SETTLED_STAYS_SETTLED_SESSION_PROMPT.md` | diff --git a/docs/architecture/05-decisions-log.md b/docs/architecture/05-decisions-log.md index 8e690753..0d9700aa 100644 --- a/docs/architecture/05-decisions-log.md +++ b/docs/architecture/05-decisions-log.md @@ -1,4 +1,4 @@ -# Журнал решений оркестратора — контракт D1–D39.265 (живой файл: карта · эрраты · живые тела · голова D39.124+ (подрезка D39.139); тела закрытых эр — в слайсах `docs/archive/architecture/`, указатель ниже; реестр всех нот — `05-decisions-index.md`) +# Журнал решений оркестратора — контракт D1–D39.266 (живой файл: карта · эрраты · живые тела · голова D39.124+ (подрезка D39.139); тела закрытых эр — в слайсах `docs/archive/architecture/`, указатель ниже; реестр всех нот — `05-decisions-index.md`) > **⟶ КАРТА АКТУАЛЬНОСТИ (ревизия D31, продлена до D38.2 [12.07]; исторические записи ниже НЕ переписываются — дисциплина D23.3).** Работая с контрактом (греп номера: живой файл → слайсы, целиком НЕ читать — D39.125), держи под рукой, что чем перекрыто: > ⚠ **Эррата 09.08 (D39.125):** D39.111 п.1 предписывал промту S3 «максимум = баланс МИНУС открытые холды» — формула ОШИБОЧНА (вычитание дважды), исправлена D39.115 п.2(а): максимум = Balance КАК ЕСТЬ; тело D39.111 — в слайсе `../archive/architecture/05-decisions-D39-106-123.md` (испр. 05.09: прежнее «живёт ниже в этом файле» протухло подрезкой D39.139) (голова D39.106+). @@ -4646,3 +4646,75 @@ Postgres — её предположение (движок работает на **9. Что осталось названным, а не построенным.** Движковая половина ряда 416 (проекция пере-покупки). Пустой шаблон `-run` в харнессе и фикстура капа на нулевой трате — оба ограничения названы ЗОНОЙ в её собственном блоке «где прибор слеп». `PD-216` открыта с снятым блокером; заведены `П-24` и `П-25`. + +## D39.266 — ПРИЁМКА БЭКЕНД-ПАКА «РЕШЁННОЕ НЕ ПЕРЕ-СПРАШИВАЕТСЯ»: ПРИНЯТ (17.09) ✅ + +**1. Что заландено.** `d25e418`, **32 пути**, $0 — платных вызовов пак не делал ни одного. 31 путь в +`backend/` (21 правленый, 10 новых) и `docs/architecture/18-bank-ontology.md`. Носитель решённого — таблица +`bank_basis`, миграция v19, аддитивная: авто-банк и `memory_version` она не двигает. + +**2. РАТИФИЦИРУЕТСЯ СМЕНА ПОВЕДЕНИЯ.** Первый прогон книги после появления базиса платит ОДИН раз за +переупаковку хвоста батчей. Замер зоны по четырём прогонам одной фикстуры: run1 `$0.001820` · run2 +`$0.001820` · run3 `$0.000000` · run4 `$0.000000`. Механизм: базис — ТРЕТИЙ вход состава батчей, run2 +встречает состав, которого у run1 не было, и не находит чекпойнта по хешу запроса. Лечение «встать в +сторону у книги, которая уже платила» ОТКЛОНЕНО: правило, решающее иначе на втором прогоне, не есть +правило резюма. Цена ограничена `gates.terminology.budget_usd` и объявлена сообщением оператору. + +**3. РАТИФИЦИРУЕТСЯ ПЯТАЯ РОЛЬ ОНТОЛОГИИ.** `docs/architecture/18-bank-ontology.md` правил пак, страница +ратифицирована `D39.158`; настоящей нотой её новая строка получает своё основание — ПАМЯТЬ РЕШЕНИЙ как +пятая сущность и вторая петля защиты подписанного. + +**4. Исходы рядов.** **490** — ЗАКРЫТ работой, и закрыт по ТРЁМ условиям, а не по одному: страж построен +(`backend/internal/membank/memvoice.go:404`=`TermWindowGaps reports a bank SURFACE`), стоит на живом пути +(`backend/internal/pipeline/seeding.go:68`=`if gaps := membank.TermWindowGaps(rows)`), логирует и НИКОГДА +не фатален — форма взята у образца голосов вместе с его гарантией, — и запинен записью каталога +`BASIS-term-window-gap-goes-unreported` с флагом `battery`. **130** — НЕ ЗАКРЫТ, и получает ТРЕТИЙ исход +вместо молчания: замысел ряда достигнут ДРУГИМ механизмом, механизм самого ряда не построен и не построен +НАМЕРЕННО (накопительный мердж авто-банка двигает `memory_version`, а базис — аддитивная таблица, которая +банк не трогает) ⇒ гейт стоп-решения владельца паком не достигается по построению, решение остаётся за +владельцем, остаток сужен до двух предметов (накопительный мердж · слоты seed-rejects). Замер зоны: +изменённых строк 1153, по каждому из трёх предметов остатка — НОЛЬ. **447** — ОТКАЗ с замером: подписанных +строк 2 из 69 и 2 из 66 ⇒ выгода ограничена 3 % прохода; вместо ряда отделено безопасное следствие — +подписанная строка больше не ДЕРЖИТ семью. Сторож растущей книги — ОТКАЗ с замером: посылка «исходник +приходит целиком» есть открытый вопрос владельцу, и сторож ответил бы за него молча. Заведён ряд **496**. + +**5. Числа приёмки — сняты МНОЙ, на замороженном дереве, каждое своим прибором.** Гейт зоны `make battery`: +`MAKE_EXIT=0`, `go list` 24 = вердиктов 24, `comm -23` пуст, FAIL 0, скипов 11 и они НАЗВАНЫ поимённо. +Стендовая цель с поданным корпусом: пять корпусных тестов, молчавших у обычной батареи, идут и проходят +(`TestK6LabelsBaseline` · `TestK6TheTwoRelaxationsPricedSeparatelyOnTheSameLabels` · +`TestCheckerLabelsBaseline` · `TestCheckerLabelsCandidates` · `TestTheInstrumentAgainstTheColdRunOracle`), +снято с `-v`, потому что без него ответа не существует. Кампания на отдельном корне штатной целью: +**315 записей гейта, 315 вердиктов, поймано 315, ВЫЖИВШИХ 0, НЕИЗМЕРЕННЫХ 0**, `MUT_EXIT=0`, +`anchors swept: 0 of 526 entr(ies) rotten`; полнота сверена в ОБЕ стороны — уникальных идентификаторов 315, +записей `battery` в каталоге того же прогона 315, обе разности пусты. M1 на копиях купленных прогонов: +A — кандидатов 69, предложено базису 68, обслужено **67 (97 %)**, пере-спрошен 1; B — 66, 65, **64 (97 %)**, +1; верность реконструкции 69/69 и 66/66 при `missing=0 extra=0`; контроли различают — `kwic_per_term` и +`kwic_width` теряют 0, положительный контроль `basis_width 40→80` теряет ВСЕ 67 и 64. Отпечаток состава +сдаваемого дерева воспроизведён методом зоны знак в знак. + +**6. ⛔ ЧТО ПРИЁМКА НАШЛА В ОТЧЁТЕ, И ЭТО ОДИН КЛАСС.** Две дыры, и обе — **не неверное число, а +отсутствующее утверждение**. (а) Один из новых тестов — не пин, а ПРИБОР: `TestProbeBankBasisM1` гейчен +`TM_BASIS_M1`, которого не ставит ни одна цель Makefile ⇒ в батарее он скипается и его зелень не значит +ничего; в докблоке файла это было названо, в отчёте — нет. (б) Ряд **130** был ЗАКАЗАН промтом и в отчёте +не упомянут ни разу при требовании исхода по КАЖДОМУ пункту. Ни шесть кругов зоны, ни её адверсариальный +контролёр, ни полный прогон каталога их не видели. ⭐ **Норма, купленная этим (формулировка зоны): +собственные проверки не находят отсутствующее, потому что знаменателем им служит СВОЙ ЖЕ текст.** Спросить +у дерева, сходится ли отчёт, автор умеет; спросить у отчёта, все ли предметы названы, — нет, список +берётся оттуда же. ⇒ перечень заказа сверяется с перечнем отчёта по СПИСКУ ЗАКАЗЧИКА, тем же движением, +что `comm -23` над пакетами батареи. ⭐ Зона закрыла обе и добавила замер, которого никто не просил: +записей каталога, чей ЛОВЕЦ env-гейчен, — **0 из 34** при знаменателе 12 env-гейченных тестов в дереве. + +**7. ⛔ МОИ ОШИБКИ ЭТОЙ ПРИЁМКИ — шесть, все пойманы приборами, не чтением.** (а) Приписал паку ТРИ +env-гейченных прибора вместо одного: две пробы пред-существуют, и поймано это диффом, а грепом файла — +нет. (б) Прочитал «31 путь» из середины предложения зоны как ИТОГ, тогда как фраза продолжалась словом +«плюс»; расхождения не было. (в) Объявил стендовую цель красной по своей вине — а флаги ставит сам рецепт +(`backend/Makefile:140`), и самообвинение спрятало бы дефект цели (ряд 496). (г) Спросил каталог мутаций +несуществующим полем `tags` и получил ноль при 526 прочитанных записях. (д) Счёл `FAIL` шаблоном, +ловившим строки-итога, и получил три падения вместо одного. (е) Дважды получил ложный ноль по `books/`: +обёртка грепа не видит каталог по `.gitignore`, а `find` не спускается в симлинк без `-L` — два РАЗНЫХ +прибора, один ноль, и оба выглядели ответом о дереве. ⇒ гардрейл про `find -L` заводится этой нотой. + +**8. Что осталось названным, а не построенным.** Платформенная половина `settled_earlier` — носитель +ряд **492**. `basis_width` не заполнен ни одной парой (пар-данность построена и запинена, живьём не +исполняется). Смена `basisFingerprintVersion` обнуляет базис каждой книги разом; механизма пере-счёта без +покупки нет. M1 не судит КАЧЕСТВО и замерен на книге из трёх глав — на длинной число может быть другим. diff --git a/docs/BACKEND_SETTLED_STAYS_SETTLED_SESSION_PROMPT.md b/docs/archive/prompts/BACKEND_SETTLED_STAYS_SETTLED_SESSION_PROMPT.md similarity index 97% rename from docs/BACKEND_SETTLED_STAYS_SETTLED_SESSION_PROMPT.md rename to docs/archive/prompts/BACKEND_SETTLED_STAYS_SETTLED_SESSION_PROMPT.md index 71c92e8b..e2d1b4fb 100644 --- a/docs/BACKEND_SETTLED_STAYS_SETTLED_SESSION_PROMPT.md +++ b/docs/archive/prompts/BACKEND_SETTLED_STAYS_SETTLED_SESSION_PROMPT.md @@ -1,5 +1,15 @@ # Бэкенд-пак: РЕШЁННОЕ НЕ ПЕРЕ-СПРАШИВАЕТСЯ — движок платит за ответ, который у него уже есть +> ✅ **АРХИВ — ПАК ОТРАБОТАН И ПРИНЯТ 17.09: акт `D39.266`** (лендинг `d25e418`, **32 пути**, $0 — платных +> вызовов моделей пак не делал). Решённая движком строка переживает покупку: носитель — таблица +> `bank_basis`, миграция v19, аддитивная. Ряд **490** закрыт по трём условиям, ряд **130** получил ТРЕТИЙ +> исход (замысел достигнут другим механизмом, стоп-решение остаётся за владельцем), два отказа сданы с +> замером, заведён ряд **496**. Числа приёмки: кампания **315/315 поймано, выживших 0, неизмеренных 0**; +> M1 — **67 из 69** и **64 из 66** обслужено из памяти. +> **Инструкции отсюда НЕ ИСПОЛНЯТЬ** (правило архива): живое — в акте `D39.266` и в рядах **492** · **496**. +> ⚠ Якоря этого файла целились в строки, которые пак и был заказан переписать: они мертвы ПО ПОСТРОЕНИЮ и +> чинить их нельзя — пере-наводка «под то, что в цели оказалось» есть подгонка под зелень. + > Выдача №14 очереди №23. Зона — `backend/`. Платных вызовов моделей пак НЕ делает: $0. > ⚠ **Числа и адреса этого промта сняты мной по дереву 17.09. Те, на которых ты строишь решение, пере-снимай сама** — > заимствованное число улики не заменяет. За смену адреса в моих источниках уезжали семь раз, а два указывали diff --git a/platform/docs/DEFECT_REGISTER.md b/platform/docs/DEFECT_REGISTER.md index 5907f723..75dfc92c 100644 --- a/platform/docs/DEFECT_REGISTER.md +++ b/platform/docs/DEFECT_REGISTER.md @@ -26,7 +26,7 @@ | PD-410 | bug | **major** | `internal/pgstore/readmodel.go`, греп `draftWork` (⚠ адрес пере-нацелен 06.09: строка уехала на ~130 позиций правками пака формы заказа); ⚠ **контраст ряда «движку передаётся ТОЛЬКО `--ceiling-usd`» БОЛЬШЕ НЕ ВЕРЕН** — `--max-units` едет в argv с 05.09 (`internal/runs/spawn.go`, греп `maxUnitsFor`), и draft-волна по ВСЕМ чанкам книги больше не фанится: её гейтит `volumeScope.allows` (`backend/internal/pipeline/volume.go`) | **Полоса и платёжная модель считают, что прогон работает над диапазоном «C глав от edit-фронта» в обеих волнах, а движок гонит волны последовательно от СВОИХ фронтов до денег — и на continuation над недочерновленной книгой (`draft_before ≥ chapters_before + C`) формула даёт `draftWork=0`: движок тратит весь потолок на черновики, полоса стоит 0/C весь прогон со stage `editing` на прогоне, который только черновит.** Зеркало дефекта, который `draftWork` чинил (тот закрывал «ready на 50%», этот открывает «0% при сделанной работе»). Это НЕ локальная ошибка формулы: любая полоса из (баз, C, D, E) где-то соврёт, пока платёжная модель («довести до конца C глав от `e0`») и движковый план работ («деньги в порядке волн от фронтов») не согласованы — лечение требует либо передавать движку план (диапазон/волны), либо выводить total полосы из движкового плана; `ceiling_chapters` сегодня до движка не доезжает вовсе. Архитектурное, ОТДЕЛЬНЫМ паком по слову оркестратора 28.08 («остановись и скажи»); подтверждено воркфлоу арифметикой на существующем зелёном пине (`TestARunOverADraftedBacklogOwesOnlyTheLastPass` держит `draftWork=0` в родственной точке) ⚠ **ПЕРЕ-ДИСПОЗИЦИОНИРОВАНА паком P12 (30.08): направление ЕСТЬ** — D39.165 §1, четыре части (цена от объёма исходника · стоп объёма в движке · хвост качества в тариф). ⛔ **(г) константу по сегодняшним числам НЕ калибровать** — гейт строка бэклога 202. Что остаётся открытым: не решение, а МЕХАНИКА, и она — отдельный пак (слово оркестратора 28.08), паком P12 не тронута. ⚠ **ПРИЧИНА СНЯТА ПАКОМ «ФОРМА ЗАКАЗА» (05.09), статус флипает ЛЕНДИНГ; и снята она НЕ так, как обещала строка 280 — расхождение названо.** Строка велела УДАЛИТЬ `draftWork`; зона этого не сделала и объясняет почему: дефект `draftWork` в том, что draft-волна фанилась по ВСЕЙ книге, а формула считала купленный диапазон. С проводкой `translate --max-units` волна больше по всей книге не фанится (`backend/internal/pipeline/volume.go`, `volumeScope.allows` гейтит и draft-волну), то есть **посылка формулы стала истинной, а сама формула — нужной**: непочерновленный остаток заказа это реальная работа прогона. Удалить её значило бы сломать полосу по-новому. ⇒ снята ПРИЧИНА, носитель оставлен. ⛔ **Испр. 06.09: здесь стояло «полоса при этом осталась в ГЛАВАХ, перевод её в юниты в этот минор не входит» — НЕВЕРНО, и это был третий носитель одной моей ошибки (отчёт зоны, состав минора, этот ряд).** `runDone`/`runTotal` первой ветвью считают в ЮНИТАХ, когда `runs.ordered_units` не null (`internal/pgstore/readmodel.go`, греп `ordered_units is not null`), и это пиньнуто `runs.TestACharacterOrdersBarIsCountedInWhatItActuallyBought`. `draftWork` при этом остаётся носителем ГЛАВНОЙ ветви — той, что считает заказ в главах, — и довод выше её и касается. ⇒ настоящее следствие: канон 0.11.0 описывает `Progress` как «in chapters» для ВСЕХ трёх форм прогона, а сборка для символьного заказа шлёт юниты; недостающий случай внесён в состав минора и отдан оркестратору 06.09. | fixed(628cc56) | воркфлоу-ревью P9 28.08 (линза bar:double-count), стоп-решение сессии P9 28.08: тянет архитектуру, не чинится в паке | | PD-424 | bug | **major** | `internal/runs/reconcile.go` `reopen` (вердикт `deferred`) и `reconcileOne`, `internal/pgstore/runs.go` `StalledRuns`, `internal/pgstore/observe.go` | **ЖИВОЙ прогон с намертво заблокированной расплатой невидим на ВСЕХ поверхностях `PD-385` и не поддаётся `run abandon` — счётчик неудач не растёт НИКОГДА.** Цепь, воспроизведённая охотником приёмки на десяти проходах: юнит исчез без маркера → `restart` → `settle` возвращает `settlementBlocked, nil` (не ошибку) → `reopen` отказывается открыть новую попытку поверх незакрытого холда и возвращает вердикт `deferred` → `case deferred: return nil` → `reconcileOne` считает проход УСПЕШНЫМ и вдобавок зовёт `ClearRunDeferral`. Итог: `reconcile_failures` 0, `reconcile_after` NULL, `StalledRuns(5)` пуст, гейдж 0, холд заморожен, движок дёргается каждым проходом. Вывести из состояния может только пользователь, нажав Stop, — и никто ему об этом не говорит. ⚠ Это ТА ЖЕ болезнь, что `PD-384`/`PD-385`, но в ЖИВОЙ фазе, куда пак P11 не дошёл: он лечил вторую фазу (расплату) и её поверхности. ⚠ **СУЖЕНА пак P12 (30–31.08), НЕ ЗАКРЫТА — половина «невидим» вылечена, половина «ручки нет» стоит.** Приор зоны принят и исполнен: блокированная расплата — НЕУДАЧА владеющей фазы, и она считается. `restart` больше не выбрасывает вердикт `settle`: на `settlementBlocked` он возвращает `errSettlementBlocked` ДО `reopen` (прежний путь платил за запрос, чтобы узнать то, что `settle` только что сказал, писал WARN, винящий рестарт в блокировке расплаты, и отвечал `nil`, который вызывающий считал успешным проходом). `reconcileOne` ключует на этом сентинеле причину — ОДНА фраза на оба фазовых пути — и ЗАДЕРЖКУ: расписание РАСПЛАТЫ, а не живой фазы, потому что открытая резервация и есть resume-гейт пользователя, и получасовой живой бэкофф держал бы его resume за блокировку, с которой он ничего сделать не может. Вердикт `deferred` у `reopen` оставлен как был: после правки он достижим только на `settlementRaced` с моментально открытой резервацией — самоисправляется следующим проходом, и фаза расплаты прямо аргументирует, что гонка не должна попадать на счётчик оператора. Гард выключения (`ctx.Err()`) стоит: счёт, придуманный ОСТАНОВКОЙ демона, — тот самый дефект, который соседняя фаза уже нашла. Итог, проверенный пином `runs.TestALiveRunWhoseSettlementIsBlockedIsCountedAndReachesTheOperator`: `reconcile_failures` доходит до порога, строка появляется в `runs --stalled` (половина `live`, не `settling`), гейдж `tm_platform_runs_stalled` = 1, отсрочка не превышает `settlementBackoffCap`. Посадка M13 КРАСНАЯ адресно. ⚠ **ЧТО ОСТАЁТСЯ ОТКРЫТЫМ и почему не взято этим паком:** терминальная РУЧКА. `run abandon` ветвится по `runs.finished_at` и на живом прогоне уходит в живую ветку, а `AbandonRun` отказывает над попыткой, ещё называющей юнит. Ручка «процесса нет, закрой деньги» — НОВАЯ разрушительная операторская поверхность над деньгами, и её дизайн (кто вправе звать, чем доказывается отсутствие процесса, что будет, если процесс вернётся) — решение своего размера, а не хвост этой правки. Сегодня пользователь выводит прогон из состояния кнопкой Stop, и теперь об этом хотя бы говорят все три поверхности `PD-385`. ⚠ **РУЧКА ПОСТРОЕНА паком «закрыть цикл» (04.09) — строка СУЖЕНА до своего остатка, не закрыта.** Форма: та же команда `tmplatformctl run abandon`, потому что рантбук уже посылает оператора именно к ней; новой команды нет. **Кто вправе звать** — оператор из CLI и только оттуда: терминальный вердикт над деньгами на HTTP-поверхность не выходит, как и `run unquarantine`. **Чем доказывается отсутствие процесса** — систему СПРАШИВАЮТ, а не верят ей на слово: команда сама зовёт `runner.Alive` по имени юнита стоящей попытки, и ответов **ЧЕТЫРЕ**, а не два — «нет» пропускает, «есть» отказывает, **недостижимая шина отказывает тоже** (отсутствие ответа не есть отсутствие процесса), и — четвёртый, найденный адверсариальным проходом уже по готовой работе — **«это НЕ ТОТ systemd» отказывает тоже**: `systemctl --user` отвечает про менеджер СПРАШИВАЮЩЕГО, а прогоны живут у пользователя демона, и там юнит, о котором чужой менеджер не слышал, неотличим от кончившегося (замерено: `ActiveState=inactive`, выход 0). Различитель — владелец `TM_PLATFORM_STATE_DIR`, ⚠ **поэтому переменная деплоя обязана быть экспортирована в оболочке оператора, иначе команда ОТКАЖЕТ** (рантбук об этом теперь говорит). Пины: `cmd/tmplatformctl/abandon_proof_test.go` — четыре ответа различителя, три отказа и путь «gone» через саму команду, плюс отказ над ЖИВЫМ транзиентным юнитом под systemd-гейтом. Второе условие проверяет хранилище ВНУТРИ транзакции: `reconcile_failures >= abandonAfter`, тот же пол, что у settling-ветви, — видеть и иметь право уничтожить это разные разрешения. **Деньги:** попытка с базовой линией и отчитанной цифрой рассчитывается по РАЗНИЦЕ (та же арифметика, что печатает `StalledRuns`), холд закрывается как `settled` с ценой в леджере; попытку без базовой линии ценить нечем — холд возвращается ЦЕЛЫМ, довод settling-ветви, доехавший до живой половины. **Что будет, если процесс вернётся** — названо прямо, потому что это цена ручки: живой движок продолжит тратить против СВОЕГО книжного потолка, а холд аккаунта уже закрыт, значит эту трату не оплатит никто и провайдеру платит ДЕПЛОЙ. Она ограничена (потолком этого же прогона) и не эксплуатируема аккаунтом: попасть в состояние можно только через прогон, который собственный реконсилятор деплоя не смог закончить. Тем же касанием закрыта долговечная половина `PD-418`. Пины: `internal/runs/abandon_orphan_test.go` — отказ без доказательства · отказ ниже пола · вердикт `orphan` со списанием по отчёту · целый холд там, где цены нет · осиротевшая попытка ЖИВОГО прогона. ⚠ **ОСТАТОК, ради которого строка остаётся открытой:** отсутствие процесса доказывается ОДИН раз, в момент команды, и между этим ответом и коммитом транзакции есть окно, в которое юнит может подняться заново. Окно узкое, его цена названа выше, но оно есть, и закрыть его может только фактически транзакционная проба — арбитр в хранилище, а не ещё одна проверка в CLI. ⚠ **ДИСПОЗИЦИЯ ПАКА «ДЕНЬГИ И ПРАВДА НА ЭКРАНЕ» (06–07.09, ЗАЛАНДЁН `fda0679`, акт `D39.221`):** остаток закрыт транзакционным арбитром, и окон оказалось ДВА, а не одно. Второе в ряду не названо: `AbandonRun` под книжной блокировкой читает ЛЮБУЮ живую попытку, поэтому разблокировавшаяся расплата плюс `restart` подставляют под доказательство о попытке N попытку N+1 с живым процессом. Доказательство приходит парой (`AbandonOrder.ProofAttemptID` + `ProofSpawns`) и сверяется в той же транзакции; расхождение — `ErrProofOvertaken`. `unit_name` в свидетели не годится (`ReleaseSpawnClaim` возвращает его в NULL), отсюда монотонная колонка `run_attempts.spawns`, инкремент внутри самого CAS `RecordSpawn` (миграция `00034`).| fixed | приёмка оркестратора №19 по паку P11 (охотник вне карты, воспроизведено 10 проходами) | | PD-440 | bug | **major** | ⚠ **два из трёх адресов УМЕРЛИ вместе с лечением, и это пере-написано, а не пере-нацелено:** `DefaultPerChapter` и `BookRunContext.ChaptersLeft` удалены паком формы заказа. Живой носитель лечения — `internal/pricing/pricing.go`, греп `func (m Model) Hold`; аргумент потолка по-прежнему `internal/runs/spawn.go`, греп `func (m meter) bookCap`; движковая половина — `backend/internal/pipeline/stagerun.go` (резерв под шаг при `waves.workers` параллельных вызовах) | **КНИГУ ЧЕРЕЗ API НЕЛЬЗЯ ДОЧИТАТЬ НИКАКИМИ ДЕНЬГАМИ — покупка перестаёт покупать.** Прирост книжного потолка за прогон равен `chaptersLeft × DefaultPerChapter`, то есть максимум `chaptersLeft × $0.03`. Движок перед редакторским шагом РЕЗЕРВИРУЕТ оценку на каждый параллельный вызов (`waves.workers`, на стенде 4 × ≈$0.069 = ≈$0.28) и останавливается на ПЕРВОЙ отказанной резервации, не дожидаясь уже летящих. Как только прирост становится меньше стоимости одного шага волны, каждый следующий прогон встаёт МГНОВЕННО и не продвигает книгу ни на юнит — а прирост только УБЫВАЕТ, потому что `chaptersLeft` уменьшается с каждой дочитанной главой. ⚠ **Воспроизведено живьём дважды подряд, платным прогоном 04.09** (книга `bk_SS5VES2JELESJSTR`, 10 глав, после первой готовой главы `chaptersLeft = 9`, прирост $0.27): прогоны `run_CR2RN76NAKYKAJE5` и `run_VSXPMJE53KJQQAOS` — оба `paused/credit_exhausted` за 10–15 секунд, `committed` не сдвинулся ни на микро-доллар (278319 до и после), холд вернулся целиком. Движковая строка обоих: `book USD ceiling reached ($0.548319) (committed=$0.278319 reserved=$0.207805, denied estimate=$0.069828) … reserve ceiling reached`. Это ПРОДУКТОВЫЙ СТОП, а не «шкала короче»: занижение ставки ×4.47 (`D39.179` п.1) до сих пор читалось как неудобство, и вот порог, за которым оно становится недостижимостью результата. ⚠ **Денег сам стоп НЕ жжёт** — отменённые вызовы этих двух прогонов не успели уйти (латентность 20 и 31 мс, `model_actual` пуст, 0 токенов); неучтённый расход — отдельная строка `PD-441`. ⚠ **Чинится СОГЛАСОВАННО, одной стороной нельзя:** поднять ставку — платформенная половина и она меняет всю шкалу покупки; не бросать летящие вызовы и/или считать резерв по фактической конкуренции — движковая. Проверка без Go: `sqlite3 -header -column "file:?mode=ro" "select trace_id, count(*), round(sum(cost_usd),6) from request_log group by trace_id;"` ⚠ **РАДИУС ПЕРЕ-СНЯТ 04.09 ЗАМЕРОМ ЗА $0 (заказ оркестратора №22): дефект НЕ про хвост длинной книги, а про ПОРОГ, ниже которого книга не переводится ВООБЩЕ.** Порог считается из измеренного, а не из оценки: движок в собственном отказе назвал резерв ОДНОГО редакторского вызова до шестого знака — `committed=$0.278319 reserved=$0.207805, denied estimate=$0.069828, ch5/chunk0/edit` при потолке `$0.548319`. Отсюда волна из четырёх стоит **$0.277633 — наблюдённая величина: три реально стоявших резерва ($0.207805) плюс отказанный ($0.069828)**. ⚠ Не `4 × $0.069828 = $0.279312`: первая редакция ряда взяла именно это произведение, а оно СКОНСТРУИРОВАНО — вызовы волны не равны между собой, промпты чанков разной длины, и `3 × $0.069828 = $0.209484` расходится с наблюдёнными `$0.207805` на `$0.001679` (средний реальный резерв $0.069268 против отказанного $0.069828). Произведение оставлено рядом как ВЕРХНЯЯ оценка, и держать оба стоит: порог считается по обоим одинаково — `$0.277633 / $0.03 = 9.25` и `$0.279312 / $0.03 = 9.31`, — то есть **вывод не зависит от выбора числа**. ⚠ Счёт «три» выведен, а не напечатан: он следует из `waves.workers: 4` минус отказанный, и подтверждается отношением `$0.207805 / $0.069828 = 2.976`. Порог — `chaptersLeft × $0.03 ≥ стоимости волны`, то есть **книга проходит только с 10 непереведённых глав и больше**. Поправка числа — оркестратора №22, 04.09. Следствия: **последние ДЕВЯТЬ глав любой книги недостижимы**, и **книга из ≤9 глав не переводится никогда** — ни первой покупкой, ни повторными, потому что потолок КУМУЛЯТИВНЫЙ (`bookCap = committed + increment`, `internal/runs/spawn.go:212-214`) и запас каждого прогона равен ровно инкременту, сколько бы книга ни потратила раньше. ⚠ **Предъявлено живьём и бесплатно:** пятиглавая книга `bk_P5UCXKHDO4HFWSH3` заведена через настоящий интейк ($0 — `manifest` без ключей), и `GET /v0/books/{id}/run-options` вернул `max_chapters: 5`, то есть **максимум, который пользователь вообще может купить этой книге, — $0.15 против $0.279312 за волну**; для книги пака после первой дочитанной главы тот же вызов вернул `max_chapters: 9` ($0.27). Разрезка короткой книги ПОБАЙТНО та же (юниты по главам 2·1·1·2·1 против тех же 2·1·1·2·1 у первых пяти глав длинной), то есть короткая книга содержит ровно тот кусок `ch5/chunk0`, чей резерв измерен. ⚠ **ЧЕГО В ЗАМЕРЕ НЕТ, называю прямо:** сама короткая книга НЕ запускалась — её прогон способен потратить до $0.15 на черновую волну, а санкция владельца на платные прогоны закрылась вместе с паком; арифметика замкнута, живой прогон короткой книги остаётся неснятым. ⚠ **ЛЕЧЕНИЕ В ДЕРЕВЕ ПАКА «ФОРМА ЗАКАЗА» (05.09), статус флипает ЛЕНДИНГ.** Константа `DefaultPerChapter` удалена целиком: цена берётся из проекции движка (`manifest --json`: `expected_usd` по главам, `step_max_usd`), а холд считается `k × ожидаемое(заказ) + step_max` — **аддитивно, не `max(...)`**, потому что последнему вызову заказа нужен запас под ЦЕЛУЮ резервацию сверх уже списанного. Пины: `pricing.TestTheLastTwoChaptersOfABookAreBuyable` (последние две главы и последняя глава покупаются), `pricing.TestTheHoldIsTheCushionedBillPlusOneWholeReservation`. ⚠ И вторая половина той же стены, найденная этим же паком: книжный `expected_usd` ВКЛЮЧАЕТ `book_once_usd` — плоские $2.00 на боевом `pipeline-c1` независимо от длины книги, — поэтому в основу холда он НЕ кладётся (иначе пятиглавая книга за $0.25 снова непокупаема); пин `pricing.TestAFlatBookLevelBoundDoesNotPutATwoDollarThresholdUnderEveryPurchase`. | fixed(628cc56) | платный сквозной прогон через API, пак «закрыть цикл» 04.09 (воспроизведено дважды) | -| PD-441 | bug | **major, деньги** | движковая половина — `backend/internal/pipeline/stagerun.go`, ветвь с комментарием `No 2xx ever arrived: nothing was billed` (`releaseReservation` + строка `request_log` с нулевой ценой); платформенная — `internal/runs/reconcile.go` `settleOne`, который берёт цифру движка как истину | **ЛЕДЖЕР ДЕНЕГ — НИЖНЯЯ ГРАНИЦА, и потолок сам её создаёт: halt отменяет вызовы, которые УЖЕ УШЛИ к провайдеру, и их цена не записывается никуда.** Замерено 04.09 на `run_FS3O4UO5EDTKVF42`: волна пустила четыре редакторских вызова, один дошёл (6846+13729 токенов, **$0.063404**, 156444 мс) и своим коммитом сорвал книжный потолок, а три оставшихся были отменены В ТОТ ЖЕ МИГ, отработав **120756, 156469 и 156470 мс** — с `cost_usd 0`, нулевыми токенами и пустым `model_actual`. Вызов, проживший 2–2.6 минуты, до провайдера дошёл почти наверняка. **Порядок величин:** соседние ЗАВЕРШЁННЫЕ вызовы того же прогона стоили $0.017409 и $0.063404 ⇒ незаписанное — порядка **$0.05–0.19 на ОДНО срабатывание потолка** против **$0.278319** за всю книгу. То есть механизм, который защищает от перерасхода, сам создаёт неучтённый расход до двух третей стоимости книги за одно срабатывание. ⚠ **Дыра не в принципе, а в ПОКРЫТИИ, и это делает строку заказом, а не наблюдением.** Консервативная оценка в движке уже построена и ратифицирована (`stagerun.go`, «paid 2xx with zero usage; settling the reservation estimate to keep the ceiling honest», pack-13 point-9): проект уже принял правило «нельзя ослеплять потолок нулём там, где вызов был платным». Но условие требует `resp` — ОТВЕТА. Вызов, отменённый в полёте, ответа не получает, уходит другой веткой, и та честно пишет «nothing was billed» — что верно для транспортного отказа, не выпустившего запрос, и НЕВЕРНО для отмены на 156-й секунде. **Направление лечения (именно направление):** сеттлить оценку и при отмене вызова, который успел уйти, различая по ФАКТУ ухода; латентность — кандидат-различитель (20 мс против 156 000 мс разводит два случая без всякого рассуждения), но порог обязан быть обоснован замером, а не назначен. ⚠ Списание провайдером НЕ ДОКАЗАНО: биллинга провайдера у зоны нет, утверждается ровно наблюдаемое — вызовы шли минутами и их цены в леджере нет. ⚠ Правка `stagerun.go` — ЧУЖАЯ зона, отсюда только строка. Смежная строка единого бэклога — **78**. Воспроизведение: `sqlite3 -header -column "file:?mode=ro" "select id, ts, stage, role, latency_ms, cost_usd, err from request_log where err='context canceled' and latency_ms > 1000;"` ⚠ **ДИСПОЗИЦИЯ ПАКА «ДЕНЬГИ И ПРАВДА НА ЭКРАНЕ» (06–07.09, ЗАЛАНДЁН `fda0679`, акт `D39.221`; ⚠ СТАТУС РЯДА ЛЕНДИНГ НЕ ФЛИПАЕТ — ряд двухзонный, и открытым его держит движковая половина, ушедшая строкой единого бэклога **331**):** платформенная половина закрыта — каждая строка `settlement` несёт БАЗИС (`pgstore.SettlementBasis`, `complete`/`halted` по тому, кончил ли движок попытку сам), операторская таблица печатает `≥` и легенду. ⛔ Формулировка «показать маржу ПОЛЬЗОВАТЕЛЮ» СНЯТА решением оркестратора №23: направление ущерба — по деплою, баланс пользователя завышен в его же пользу, показывать ему нечего. Движковая половина названа поимённо и ушла строкой бэклога.| open | платный сквозной прогон через API, пак «закрыть цикл» 04.09 (усилено разбором оркестратора №22 по коду движка) | +| PD-441 | bug | **major, деньги** | движковая половина — `backend/internal/pipeline/stagerun.go`, ветвь с комментарием `No 2xx ever arrived: nothing was billed` (`releaseReservation` + строка `request_log` с нулевой ценой); платформенная — `internal/runs/reconcile.go` `settleOne`, который берёт цифру движка как истину | **ЛЕДЖЕР ДЕНЕГ — НИЖНЯЯ ГРАНИЦА, и потолок сам её создаёт: halt отменяет вызовы, которые УЖЕ УШЛИ к провайдеру, и их цена не записывается никуда.** Замерено 04.09 на `run_FS3O4UO5EDTKVF42`: волна пустила четыре редакторских вызова, один дошёл (6846+13729 токенов, **$0.063404**, 156444 мс) и своим коммитом сорвал книжный потолок, а три оставшихся были отменены В ТОТ ЖЕ МИГ, отработав **120756, 156469 и 156470 мс** — с `cost_usd 0`, нулевыми токенами и пустым `model_actual`. Вызов, проживший 2–2.6 минуты, до провайдера дошёл почти наверняка. **Порядок величин:** соседние ЗАВЕРШЁННЫЕ вызовы того же прогона стоили $0.017409 и $0.063404 ⇒ незаписанное — порядка **$0.05–0.19 на ОДНО срабатывание потолка** против **$0.278319** за всю книгу. То есть механизм, который защищает от перерасхода, сам создаёт неучтённый расход до двух третей стоимости книги за одно срабатывание. ⚠ **Дыра не в принципе, а в ПОКРЫТИИ, и это делает строку заказом, а не наблюдением.** Консервативная оценка в движке уже построена и ратифицирована (`stagerun.go`, «paid 2xx with zero usage; settling the reservation estimate to keep the ceiling honest», pack-13 point-9): проект уже принял правило «нельзя ослеплять потолок нулём там, где вызов был платным». Но условие требует `resp` — ОТВЕТА. Вызов, отменённый в полёте, ответа не получает, уходит другой веткой, и та честно пишет «nothing was billed» — что верно для транспортного отказа, не выпустившего запрос, и НЕВЕРНО для отмены на 156-й секунде. **Направление лечения (именно направление):** сеттлить оценку и при отмене вызова, который успел уйти, различая по ФАКТУ ухода; латентность — кандидат-различитель (20 мс против 156 000 мс разводит два случая без всякого рассуждения), но порог обязан быть обоснован замером, а не назначен. ⚠ Списание провайдером НЕ ДОКАЗАНО: биллинга провайдера у зоны нет, утверждается ровно наблюдаемое — вызовы шли минутами и их цены в леджере нет. ⚠ Правка `stagerun.go` — ЧУЖАЯ зона, отсюда только строка. Смежная строка единого бэклога — **78**. Воспроизведение: `sqlite3 -header -column "file:?mode=ro" "select id, ts, stage, role, latency_ms, cost_usd, err from request_log where err='context canceled' and latency_ms > 1000;"` ⚠ **ДИСПОЗИЦИЯ ПАКА «ДЕНЬГИ И ПРАВДА НА ЭКРАНЕ» (06–07.09, ЗАЛАНДЁН `fda0679`, акт `D39.221`; ⚠ СТАТУС РЯДА ЛЕНДИНГ НЕ ФЛИПАЕТ — ряд двухзонный, и открытым его держит движковая половина, ушедшая строкой единого бэклога **331**):** платформенная половина закрыта — каждая строка `settlement` несёт БАЗИС (`pgstore.SettlementBasis`, `complete`/`halted` по тому, кончил ли движок попытку сам), операторская таблица печатает `≥` и легенду. ⛔ Формулировка «показать маржу ПОЛЬЗОВАТЕЛЮ» СНЯТА решением оркестратора №23: направление ущерба — по деплою, баланс пользователя завышен в его же пользу, показывать ему нечего. Движковая половина названа поимённо и ушла строкой бэклога. ⚠ **ЗАКРЫТО 17.09 ПРИЁМКОЙ ПАКА «ПРОГОН НЕ ВРЁТ О СЕБЕ»; статус проставлен зоной по норме «закрытие — коммит плюс пинящий тест». Ряд ПРОТУХ, а не был забыт, и механизм протухания стоит назвать: его текст последний раз менял `fda0679` (07.09) — лендинг ПЛАТФОРМЕННОЙ половины, — то есть строка писана ДО того, как приехала движковая (`3f05fab`, 10.09), и описывает мир, которого в дереве больше нет. Вдобавок она ссылается на строку единого бэклога **331**, которой в таблице нет с того же дня.** **Что в дереве вместо дефекта** (адреса пере-сняты зоной, не приняты со слов): доставленный обрыв перехвачен ДО нулевой ветки — `backend/internal/pipeline/stagerun.go:746`=`if errors.As(err, &cut) && cut.Delivered {`, — и книжится ОЦЕНКОЙ РЕЗЕРВАЦИИ с чекпойнтом (`backend/internal/pipeline/cutcall.go:101`=`func (r *Runner) settleCutCall`, ветка `:112`=`if cut.Billable {`); вторая половина, публикация оценочных строк, — `backend/internal/pipeline/paidtail.go:210` (его собственный комментарий говорит «It is the engine's half of PD-441») и `backend/internal/pipeline/status.go:942`=`rep.EstimatedRows, rep.EstimatedUSD = estimatedSpend(usage, committed)`. **Пины, поимённо:** `backend/internal/pipeline/cutcall_test.go:596`=`func TestSettleUSDForCutCallIsTheReservationEstimate` · `cutcall_test.go:1074`=`func TestMoneyWithNoCheckpointLeftIsStillAnEstimate` · `burnedpregates_test.go:1142`=`func TestTheCutRowPublishesItsEstimateAndItsGap` · `backend/cmd/tmctl/render_test.go:602` (поверхность говорит «≥ X» и НИКОГДА «≥ X, до Y», ряд назван там по номеру). **Ратифицировано `D39.234` п.4**, который и называет 331 движковой половиной этого ряда со словами «её условие закрытия … исполнено». ⚠ **Двусторонние ссылки на живые остатки темы, которые НЕ являются предметом этого ряда и имеют своих носителей:** строка единого бэклога **376** — различитель сужен до «провайдер ответил 2xx» (`backend/internal/llm/attemptcut.go:221`=`Billable: answered && tr.afterHeaders()`), направление сужения — НЕДОсчёт, ратифицировано; строка **382** — пометка «это ОЦЕНКА» по шву не едет, и следствие в деньгах именно платформенное: зона умеет сказать «≥ X» и никогда «≥ X, до Y». Замер зоны 17.09: `estimated_rows` \| `estimated_usd` \| `EstimatedRows` \| `EstimatedUSD` в `platform/` — **0 хитов при 221 прочитанном `.go`**, контроль на населённость прибора — те же имена в `backend/` дают **10**. ⚠ Приёмка тем же вопросом получила 9: шаблоны разные (зона брала и `snake_case`, и `CamelCase`), и это не спор о числе, а два прибора. | fixed(3f05fab) | платный сквозной прогон через API, пак «закрыть цикл» 04.09 (усилено разбором оркестратора №22 по коду движка) | | PD-438 | bug | **major** | `internal/ingest/tail.go` `apply` (греп `ErrForeignStreamAhead`), `internal/ingest/tail.go` `tailFrom` (греп `mine := want`), `internal/runs/reconcile.go` `drainJournal` | **Владение потоком не переживало проход свипа, и чужие события ложились на оплаченную попытку.** `mine` — возвращаемое значение, а не колонка: следующий проход выводит его заново из `pos.LastSeq > 0`. Пока тейлер ПРОХОДИЛ мимо чужого handshake'а, двигая байтовый хинт, следующий проход читал чужую область с курсором, который говорит «это наше»: чужой `ceiling` ставил `paused` живому оплаченному прогону, `unit_done` писал главы, которых никто не покупал, а чужой `seq`, попавший на наш, давал `ErrPayloadConflict` и карантинил здоровую проекцию. ⚠ **Воспроизведено в двух вариантах, до и после правки P13** (копия дерева, `Tail` дважды — форма, в которой его зовёт `drainJournal`): на `HEAD 494c4ef` законный чужой hello травит проекцию (`pass 2 applied a FOREIGN event (seq [2])`), а чужой мажор карантинит; после пере-упорядочивания пункта 3 P13 ОБА травят — то есть заказанная правка расширила старый класс с законных чужих строк на любые. Конфликт payload воспроизводится одинаково на обеих версиях. ⚠ Лечение в дереве пака P13 (03.09): чтение ОСТАНАВЛИВАЕТСЯ на чужом handshake'е, если платформа именовала поток попытки и наши строки уже применены (`pos.LastSeq > 0`), и курсор на нём остаётся — владение выводится заново каждый проход, ценой одного пере-чтения строки. Прежняя семантика «пройти мимо» сохранена там, где она безопасна: пока `LastSeq == 0`, наш handshake ещё может лежать ниже по файлу (пин `TestAForeignStreamBeforeOursIsWalkedPastRatherThanStoppedOn`), и у безымянной легаси-попытки (`want == ""`) — пин `TestAnotherAttemptsStreamInTheSameJournalIsSkipped` зелёный. Пины: `TestAForeignStreamDoesNotOwnOurAttemptOnTheNextPass` (три формы чужого hello × три следующих строки). ⚠ **ДОФИКС 03.09: обоснование «вред ограничен по времени» ОПРОВЕРГНУТО приёмкой исполнением, и оно было моё.** Довод «чужой handshake ⇒ нашего процесса в книге уже нет» неверен: платформа отдаёт КАЖДОМУ спавну одной и той же попытки один и тот же id потока (`internal/runs/spawn.go`, греп `engineStreamID(l.RunID, l.AttemptNo)`), а движок, найдя, что этот id уже писал события книги, минтит СВЕЖИЙ и продолжает (`backend/internal/pipeline/events.go`, греп `fresh := obs.NewTraceID()`). Значит «чужой» hello может писать ЖИВОЙ процесс нашей же попытки, и прогон способен простоять припаркованным весь свой срок. Радиус сужен опровергателем приёмки: путь — конъюнкция двух признанных сбоев (претензия на юнит, отчитавшаяся ошибкой, плюс исчезновение юнита без exit-marker), а не рядовой рестарт. **Наблюдаемость дана в том же дофиксе:** тейлер сообщает о парковке отдельным сигналом (`internal/ingest/tail.go`, греп `ErrForeignStreamAhead`) вместо тихого `nil`; свип пишет WARN с прогоном, попыткой и смещением; и парковка теперь СТОИТ РЯДОМ с карантином в условии канала починки (`maybeResync`, греп `!l.Quarantined && !parked`), то есть у припаркованной попытки снова есть свежесть через `tmctl status`. Пины: `TestTheParkIsReportedSoTheCallerCanTellItFromBeingCaughtUp` (без DSN), `TestAParkedAttemptStillGetsTheRepairChannel` (DSN). ⚠ Чего по-прежнему НЕТ: строки в `runs`, гейджа и колонки — парковка живёт длину одного прохода и в БД не пишется; дать ей строку значит завести колонку, то есть миграцию, а она этим нарядом не заказана ⚠ **ОСТАТОК НАЗВАН 04.09 приёмкой:** лечение в дереве и заленджено (`6ae3e76`), но ПРИПАРКОВАННАЯ попытка не видна ни в `runs`, ни гейджем, ни колонкой — у этого класса нет ни одного из трёх сигналов, которые были у карантина, а `maybeResync` до дофикса такую попытку пропускал. Дофикс дал ей имя (`ErrForeignStreamAhead`), WARN с троттлингом и вход в ресинк; поверхностная видимость для ОПЕРАТОРА остаётся открытой и идёт райдером платформенного пака. ⚠ **ДИСПОЗИЦИЯ ПАКА «ЗАКРЫТЬ ЦИКЛ» (04.09): ОТЛОЖЕНО СОЗНАТЕЛЬНО, и вот довод, а не отсутствие времени.** Все три недостающих сигнала — строка в `runs`, гейдж, колонка — читают ХРАНИЛИЩЕ, а парковка в хранилище не пишется: она живёт длину одного прохода и выводится заново каждым свипом. Дать ей любой из трёх значит завести колонку на `run_attempts`, то есть миграцию и новое состояние, которое надо СНИМАТЬ, — а снимать его некому, кроме того же свипа, который его поставил. Это не райдер, а отдельная работа со своим дизайном («парковка как СОСТОЯНИЕ, а не как исход прохода»), и сделать её заодно с дверью выдачи значило бы решить её мимоходом. Что у класса ЕСТЬ сегодня: имя (`ErrForeignStreamAhead`), WARN с троттлингом и вход в канал починки — оператор, который смотрит в ЖУРНАЛ, парковку видит; невидима она тому, кто смотрит только в таблицу. Строка остаётся открытой ровно на этом. ⚠ **ДИСПОЗИЦИЯ ПАКА «ДЕНЬГИ И ПРАВДА НА ЭКРАНЕ» (06–07.09, ЗАЛАНДЁН `fda0679`, акт `D39.221`):** остаток видимости закрыт колонкой `run_attempts.parked_at` (миграция `00034`), гейджем `tm_platform_parked_attempts` и своей ячейкой PARKED в `tmplatformctl runs`. Довод прошлого пака против колонки на проверке не устоял: парковка не состояние жизненного цикла, а проекция, пере-выводимая из (курсор, журнал) каждым проходом, поэтому снимает её тот же проход — в отличие от карантина, который снимает человек. Метка ставится ОДИН раз, чтобы «припаркован с какого момента» имело ответ.| fixed | самопроверка пака P13 (веер, линза шва; воспроизведено сессией на копии) | ## Открытые — minor