textmachine/docs/BACKEND_SETTLED_STAYS_SETTLED_SESSION_PROMPT.md

366 lines
44 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Бэкенд-пак: РЕШЁННОЕ НЕ ПЕРЕ-СПРАШИВАЕТСЯ — движок платит за ответ, который у него уже есть
> Выдача №14 очереди №23. Зона — `backend/`. Платных вызовов моделей пак НЕ делает: $0.
> ⚠ **Числа и адреса этого промта сняты мной по дереву 17.09. Те, на которых ты строишь решение, пере-снимай сама** —
> заимствованное число улики не заменяет. За смену адреса в моих источниках уезжали семь раз, а два указывали
> в НЕСУЩЕСТВУЮЩИЕ файлы.
## 1. Какая проблема и что решит твой результат
На каждой покупке глав движок заново платит банк-ролям — терминологу и классификатору — за термины, которые уже
решены. Замерено на двух купленных прогонах: на подписи сменились **12 из 69** и **14 из 66** передач, и словом,
а не регистром, — 10 из 12 и 12 из 14. При этом собственная улика не менялась у **25 из 26** строк: мы платим за
пере-решение без новой информации, а ответ может разойтись с тем, что уже стоит в отгруженных главах.
Цена конкретна. Потолки банк-ролей **пожизненные**`budget_usd: 1.00` и `classify_budget_usd: 1.00`
(`backend/configs/pipeline-c1.yaml`); исчерпание необратимо, и книга остаётся без консолидированного банка
навсегда, о чём не говорит ни одно сообщение (ряд **356**). Длинная книга при сегодняшней пере-покупке съедает
потолок примерно за 616 покупок.
Твой результат: строка, решённая движком, переживает покупку — её ответ берётся из носителя, а не покупается
снова, и пере-спрашивается она только при названном событии.
## 2. Зона записи и git
Пишешь `backend/` и свою секцию в `docs/PROGRESS.md`. **Не коммитишь** — дерево передаёшь мне, лендинг мой.
Чужие незакоммиченные файлы не трогаешь. `.env` не читаешь никогда.
## 3. Карта чтения — ЗАКОН, пять позиций
1. `CLAUDE.md` в корне — канон проекта целиком.
2. `backend/internal/pipeline/terminologist.go` — **платный путь банк-ролей: сборка кандидатов, фильтр решённых
(`dropBankSettled`, вызов на `:401`), батчи, разбор ответа и то, что делается с ним дальше.** Читать целиком,
включая докблок `:1347-1395`: там записано, ПОЧЕМУ сегодняшний фильтр устроен из двух условий, и эта причина —
твоя главная опора и главное ограничение.
3. `backend/internal/pipeline/mining.go` — эмиссия дельты, авто-банк и **граница сигнатурной остановки**.
4. `docs/architecture/18-bank-ontology.md` — что такое банк, чьё слово в нём живёт, и три правила дисциплины
носителей. Страница короткая, читать целиком: твой пак её правит.
5. `docs/research/35-bank-memory-consilium.md` — §1.2 (П1), §1.5, §2.0. ⛔ **Читать как ПРОЕКТ, не как
ратифицированное:** документ сдан БЕЗ сходимости, правилом остановки; свёртка N-2 в N-1 сделана после
последнего круга проверки и **не судилась ничем**; четыре минора судьи на момент сдачи внесены не были;
часть адресов писана по копии кода от 15.09 и указывает в файлы, которых нет.
## 4. Что построить
### 4.1. Замер M1 — ПЕРВЫМ БЛОКОМ, и второй блок без моего ответа не начинается
Форма предиката без замера не принимается — это условие §4 итога консилиума, и оно не формальность: предикат
решает, за что мы платим.
Отпечаток и предикат делай чистыми функциями. Прибор — env-гейченный тест по образцу корпусных пинов
(`D39.255` п.2), который гоняет их **над копиями** купленных баз и печатает: кандидатов · решённых ·
пере-спрошенных по классам (родня подписанных · нерешённые `auto` · новые · сменилась улика).
**Два контроля обязательны, и оба различающие:**
- подменить исходник вокруг ОДНОГО вхождения одного кандидата ⇒ пере-спрошен ровно он и его юнит;
- два прогона под одним базисом ⇒ состав батчей байт-идентичен.
⚠ Контроль «два одинаковых прогона дали 0 % пере-спроса» ВЫРОЖДЕН: он меряет детерминизм харнесса, а не силу
предиката. Не засчитывай его.
**Материал замера — ТРИ вещи, а не одна, и это найдено опровергателем промта.** Из базы отпечаток не считается:
таблицы чанков в схеме НЕТ (контроль: в `tm-coldrun-b/evidence/paid-final-project.db` таблиц 17, в
`tm-coldrun-a/evidence/v16-readonly/project.db` — 16, `chunks` среди них ноль). Нужны: **(1)** копия базы — ответы ролей,
банк, чекпойнты; **(2)** ИСХОДНИК книги, он лежит отдельно: `/home/ubuntu/tm-coldrun-a/material/guzhenren-ch1-3.gb18030.txt`
(⚠ кодировка gb18030) и `evidence/*/source.txt`; **(3)** `book.yaml` того прогона. Отпечаток, посчитанный по единственному
тексту, который база хранит, — по ОТВЕТАМ модели, — измерил бы не тот предмет.
**Сырьё куплено и невосстановимо. Работай на КОПИЯХ.** Базы: `/home/ubuntu/tm-coldrun-a` (14 баз,
`evidence/v16-readonly/project.db`) и `/home/ubuntu/tm-coldrun-b` (26 баз, `evidence/paid-final-project.db`,
`evidence/paid-bankstop/project.db`). База прогона A несёт схему 16 при голове 18: `OpenReadOnly` её отвергает,
а `Open` МИГРИРУЕТ (ряд **475**). Я пере-снял: миграции v17/v18 аддитивны — `CREATE TABLE IF NOT EXISTS` и
`ALTER TABLE … ADD COLUMN`, ни одного `DROP`/`RENAME`/`DELETE FROM`, — то есть на копии `Open` безопасен, а
оригинал не открывай вовсе. `sqlite3` как CLI на машине НЕТ: python3 + модуль `sqlite3`, режим `mode=ro`.
Числа блока 1 — в отчёт. **Блок 4.2 не начинается, пока я не принял форму предиката.**
### 4.2. Базис — ИСТОЧНИК ОТВЕТОВ, а не фильтр. Это несущее, и здесь самая тихая регрессия пака
Соблазн описать N-1 как «фильтр снимает решённого кандидата» — и этого НЕДОСТАТОЧНО. Проверено чтением:
снятый кандидат не попадает в консолидированные, а `attachConsolidatedDst` стампит передачу только при непустом
значении — её докблок говорит дословно: «Terms the role did not answer are left untouched»
(`backend/internal/pipeline/terminologist.go:1291`=`Terms the role did not answer are left untouched`). Дальше
двухрежимная эмиссия ставит `draft` ТОЛЬКО при непустом `dst`
(`backend/internal/miner/miner_emit.go:279`=`st.Dst, st.Status = m.Dst, "draft"`), иначе строка остаётся `auto`.
⇒ Наивный фильтр молча ОБНУЛИТ уже купленную передачу: авто-банк потеряет её, а таблица стопа и проекция
покажут строку неотвеченной. Прогон станет выглядеть дешевле, а банк — беднее. Это ровно тот класс, за который
здесь бьют: выгода видна, потеря молчит.
**Поэтому базис подставляет ответ** — передачу, тип, род — там, где роль не спрашивали. Перечисли в записке
ВСЕХ читателей ответа и покажи в отчёте, что каждый получил своё; начни с `attachConsolidatedDst`,
`attachClassifiedGender` (`backend/internal/pipeline/terminologist.go:1306`=`attachClassifiedGender stamps`), их соседа по типу, `consolidatedRows`, строк стоп-таблицы и
проекции консолидации.
⛔ **И ДВА читателя, которых докблок фильтра называет ПРИЧИНОЙ своей двух-условности — мой первый список их упускал,
нашёл опровергатель промта.** `backend/internal/pipeline/terminologist.go:1352`=`CanonConflicts and ConsolidationKeyConflicts` говорит прямо:
роль спрашивают о банкованных поверхностях НАРОЧНО, потому что её ответ читают эти две проверки, и они ставят
владельцу на лист отметку «книга уже называет термин иначе». Вызовы живые —
`backend/internal/pipeline/terminologist.go:624`=`terminology.CanonConflicts(cands, out, canon)` и
`backend/internal/pipeline/terminologist.go:646`=`membank.ConsolidationKeyConflicts(consolidatedRows(cands, out), bank)`.
**реши и объяви ЯВНО: судится ли подставленный базисом ответ этими двумя.** «Да» — отметки поедут на лист за
передачу, которую в эту покупку никто не покупал, и поедут на КАЖДОЙ покупке. «Нет» — отметки исчезнут у населения,
ради которого фильтр и сделан двух-условным. Молчание здесь — выбор вслепую, и он денежный.
**Отдельно `Invented`:** `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/terminologist.go:618`=`res.Consolidated++` сменит
смысл, если базисные ответы влить в общий набор до цикла счёта.
Список мой — проверь его полноту сама, я уже дважды не увидел читателя, которого называет сам код.
### 4.3. Две границы записи — ДЕЛАЙ РОВНО ТАК, потому что одной недостаточно по построению
Базис пишет ПРОГОН на своих выходных границах, и границ **две**:
- `run-finished``backend/internal/pipeline/bookrun.go:258`=`r.exportBank(ctx, "run-finished")`, и она стоит
под `if err == nil` (`backend/internal/pipeline/bookrun.go:254`=`if err == nil {`);
- `bank-mining/signature-stop``backend/internal/pipeline/mining.go:270`=`bank-mining/signature-stop`.
Одной мало не по вкусу, а по коду: сигнатурная остановка возвращается ЗНАЧЕНИЕМ-ОШИБКОЙ —
`backend/internal/pipeline/waverun.go:185`=`return nil, &WaveSignatureStop{` (тип объявлен `:89`, метод `Error()`
на `:104`). ⇒ прогон, кончившийся стопом подписи, базиса бы не написал вовсе, и резюм после подписи оплатил бы
весь проход.
**Чего делать НЕЛЬЗЯ: писать базис сразу после платного прохода, до развилки.** Базис, присутствующий на
краш-резюме, сжимает состав батчей, чекпойнты не находятся, и резюм перекупает то, что уже оплачено.
**Место в порядке записи названо, потому что на границе стопа порядок — инвариант:** карта → таблица стопа →
проекция банка → **базис** → память флажка. ⚠ **Это отклонение от буквы консилиума (он ставил базис пятым,
последним), и довод взят у самого кода — нашёл опровергатель промта.** Комментарий над записью памяти флажка
формулирует правило: `backend/internal/pipeline/mining.go:271`=`a crash between the two costs one benign re-stop` — последней
пишется запись, чья потеря ДЕШЕВЛЕ. Потеря памяти флажка стоит одного лишнего доброкачественного стопа; потеря
базиса стоит пере-покупки банк-ролей из ПОЖИЗНЕННОГО потолка (ряд **356**). ⇒ базис идёт раньше. Выберешь иначе —
назови, чем громкая строка компенсирует окно краша, и запини это.
Ветка отказа по форме такая же, но громче по последствию: **стоп остаётся стопом, а неудача записи базиса обязана
КРИЧАТЬ** — она означает, что резюм пере-спросит роли, то есть это денежное событие, а не строка бухгалтерии.
**Писатель ОДИН — прогон; границ у него две.** Формулируй именно так. Онтология судит носитель с двумя
писателями так же строго, как проекцию без читателя (`docs/architecture/18-bank-ontology.md:70-72`=`Отсюда правило таблицы выше`), и
консилиум на этом уже спотыкался.
### 4.4. Форма отпечатка — РЕШИ САМА, но развилку знай: от неё зависит, переживёт ли пак следующую работу
Отпечаток — хеш того, что читает роль. Консилиум пишет «строки `ctx`». ⛔ **Так делать опасно**, и вот почему:
`ctx` — это окна KWIC, а их отбор, число и ширина управляются тремя независимыми ручками
(`AttachKWIC`, `backend/internal/terminology/terminology.go:340`=`func AttachKWIC`; вызов
`backend/internal/pipeline/terminologist.go:310`=`terminology.AttachKWIC(cands, chunks`; ключи `kwic_per_term`/`kwic_width` — пар-данные). Любая из них молча обнулит набор
решённых у КАЖДОЙ книги: отпечатки не совпадут ни у одного кандидата, и книга потратит остаток пожизненного
потолка на пере-консолидацию.
Это не гипотеза: стратифицированный отбор окон — заказанная работа (ряд **449**, контроль: `stratif`**0**
совпадений при 53 не-тестовых Go-файлах двух пакетов), и она придёт.
⇒ Ищи форму, **инвариантную к способу выбора окон**: текст вокруг вхождений ключа, а не то подмножество, которое
отобрали для роли. ⛔ **Но ширину отпечатка НЕ зашивай константой в Go** (моя первая редакция велела именно это —
поймал опровергатель): `D39.50` п.4 ратифицировал, что «`kwic_width` в РУНАХ = утечка пары в общий слой» и вынес ширину
в пар-данные, построено `D39.51`/`D39.53`, носитель — `backend/internal/lang/langpack.go:744`=`kwic_per_term`. Константа в Go стала бы
единственной шириной и была бы пар-слепой по случайности, причём на ДЕНЕЖНОМ предикате. ⇒ ширина — пар-данное с
движковым умолчанием, и в отчёте ответь на ревью-вопрос канона: заработает ли пара, которой в репозитории нет, без
правки Go. Инвариантность достигается тем, что отпечаток не читает ОТОБРАННЫЕ окна, а не тем, что ширина зашита. Якорь канона бери **по кандидату**, не по
батчу: `CanonFor` принимает батч (`backend/internal/terminology/terminology.go:856`=`func CanonFor(batch []Candidate`), и отпечаток по батчу вернул бы зависимость от состава,
от которой пак как раз уходит. В отпечатке НЕТ вариантов черновиков, `freq` и `since_ch`.
**Посылка «исходник книги приходит целиком» — ОТКРЫТЫЙ вопрос владельцу от 17.09, а не допущение пака**, и это
поправка опровергателя к моей первой редакции. Шапка журнала решений говорит: для РАСТУЩЕГО сериала посылка ложна
по построению, и вопрос вынесен владельцу отдельно. ⇒ сторож «хеш исходника разошёлся — кричим» у растущей книги
срабатывал бы на каждом выпуске и обнулял базис целиком, то есть молча отвечал бы за владельца. Заголовок носителя
всё равно несёт версию схемы отпечатка и хеш исходника, но сторож обязан **различать «исходник дописан в конец» и
«исходник подменён»**: в первом случае решение старых строк падать не обязано. Не строишь различение — объяви
растущую книгу вне скоупа ЯВНО и напиши, что механизм делает при разошедшемся хеше.
### 4.5. Условие «решено» — и состояние, которое движок считает невозможным
Предикат требует: строка движка со статусом **`draft`** и непустой передачей · отпечаток совпал с записанным ·
то же верно для всех членов её юнита.
**Статус спрашивать ОБЯЗАТЕЛЬНО, «непустой передачи» мало.** Майнер производит пару `status:auto` с непустым
`dst`: `backend/internal/miner/miner_emit.go:268`=`st.Dst = props[0].Dst` — ветка при `props[0].Via == ""`
статуса не трогает, и он остаётся `auto`. Четыре комментария движка объявляют эту пару невозможной; пина нет ни
одного. Это ряд **487**, твой пак его НЕ чинит — но посылку «решено ⇒ draft» запини, иначе починка ряда 487
завтра скачком двинет набор решённых, то есть деньги.
**И про «юнит целиком» знай ограничение.** Семьи и серии детектируются НАД `paid`, то есть ПОСЛЕ фильтра
(`backend/internal/pipeline/terminologist.go:486`=`terminology.DetectFamilies(paid, fp)`, блок 483487), и комментарий `:481-482` объясняет причину: детектировать над полным набором
значит рассогласовать юниты с батчами, из них построенными. ⇒ это развилка, а не приказ: либо юнит для
предиката считается отдельным проходом, не трогая батчер, либо «семья целиком» сужается и это называется.
Решение — в записку-план.
### 4.6. Носитель — развилка, и я её НЕ закрываю за тебя
Класс ратифицирован: «ПАМЯТЬ РЕШЕНИЙ» — писатель прогон, момент граница, читатель предикат до первой траты
(эррата 17.09-д в шапке `docs/architecture/05-decisions-log.md`). Форму носителя класс не фиксирует.
- **Файл рядом с базой** — буква консилиума (`bank-basis.yaml`). Образец готов:
`backend/internal/pipeline/mining.go:703`=`return r.Book.ProjectDB + ".auto-bank.yaml"`, запись атомарная
(`backend/internal/pipeline/artifact.go:26`=`func writeFileAtomic`).
- **Таблица хранилища** — аддитивная миграция по образцу памяти флажка: денежный предикат не читает файл,
который правится рукой; запись атомарна и идёт в своей транзакции. Образец — `backend/internal/store/stopmemory.go:33`=`func (s *Store) MarkStopPresented`
(55 строк: «dumb storage», предикат живёт в пайплайне, набор только РАСТЁТ и удаления нет намеренно).
**Общей транзакции с чекпойнтами у образца НЕТ** — моя первая редакция приписала ему эту гарантию, поймал
опровергатель (контроль: слово `checkpoint` в файле — 0 вхождений). Нужна такая транзакция — это НОВОЕ свойство,
его строят и называют ценой, а не наследуют.
Назови выбор и довод в записке-плане. ⛔ Отпечаток в СТРОКЕ авто-банка — мёртвая форма: `writeAutoBank` в
продакшне зовётся ровно один раз, внутри ветки «не останавливаемся» (`backend/internal/pipeline/mining.go:242`=`r.writeAutoBank(ctx, mined, proposals` под `if !stopping` на
`:235`), то есть на стопе подписи ему негде лечь.
### 4.7. Что пак задевает наружу — поле контракта
Сегодня `never_asked` в проекции равно числу снятых банком (`backend/internal/pipeline/bankexport.go:118`=`NeverAsked: t.BankSettled`) и
означает «сид держит поверхность и все черновики согласны». Поле живёт в каноне
(`docs/architecture/14-api-contract/openapi.yaml`) и читается платформой в десятке мест. ⇒ строки, решённые
базисом, в это поле класть НЕЛЬЗЯ без смены смысла: заводи **аддитивное** поле, это минор контракта, и назови
его в отчёте — пинг платформе даю я.
**И носителей этого смысла БОЛЬШЕ ОДНОГО: три фразы солгут дословно, если их не тронуть** (находка
опровергателя). Экран подписи: `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`. Для строки, решённой базисом, обе половины фразы ложны — банк
поверхность не держит, и черновиков об этом не спрашивали. Это ровно класс «сообщение лжёт о собственной причине»,
который код уже запрещает у соседа (`D39.93` п.2). ⚠ И отметка `SettledByBank` на шов НЕ едет вовсе: проекция несёт
`Invented`, `Contradicts`, `BankHolds` (`backend/internal/pipeline/bankexport.go:251`=`Contradicts: row.Contradicts, BankHolds: row.BankHolds`) и её не
переносит ⇒ аддитивное поле проекции и есть единственный шовный носитель нового состояния.
### 4.8. Хвост, который сбрасывается без вреда для пака
- **Ряд 490 — страж РАЗРЫВА окон глав у банковых строк.** Загрузчик ловит пересечение, разрыв не ловит никто;
готовый образец для другой сущности — `backend/internal/membank/memvoice.go:271`=`func VoiceWindowGaps`.
Бери у образца не только форму, но и гарантию: намеренный разрыв законен, поэтому исход — громкая строка, а
не отказ загрузки. $0.
- **Ряд 447** — подписанная поверхность снова спрашивается у роли во втором проходе. ⚠ Это смена продуктового
поведения: сегодняшний фильтр платит за разнобой черновиков НАРОЧНО (докблок `:1350-1357` объясняет, зачем).
Берёшь — объявляй как смену поведения, а не как починку.
- **Ряд 448** — предупреждение о разовой цене после N-1 станет лгать. ⛔ **ИСПР.: моя первая редакция писала «текста
в коде УЖЕ НЕТ, 0 совпадений» — это ЛОЖЬ, найденная опровергателем.** Текст жив дословно:
`backend/internal/pipeline/terminologist.go:541`=`This is a ONE-TIME cost; every later run replays for $0` (он в хвосте длинной строки —
я обрезал вывод по ширине и прочёл обрезок как факт). Устарел только адрес ряда (`:498`). **Носителей ТРИ:** сама
строка · голден каталога операторских сообщений `backend/internal/pipeline/testdata/operator-messages.txt:136`=`terminology: this book had already paid`,
который гейтит отдельный тест · два пина `backend/internal/pipeline/banksettled_test.go:193`=`func TestAResumeFindsItsCheckpointsAfterTheFilter` (резюм: ноль обращений к провайдеру, $0,
и вдобавок ОТСУТСТВИЕ ключа `reconsolidated=true` в логе) и `:417` (обе половины: молчать на свежем прогоне,
сработать в описанном случае). ⇒ пере-формулировка обязана обновить И голден: это не подгонка под зелень, а
обслуживание заказанной смены поведения (`D39.183`), и она ОБЪЯВЛЯЕТСЯ в отчёте.
### 4.9. Что в пак НЕ входит — чтобы молчание не читалось отказом
**N-3** (одна строка закона на ключ) — нужен замер M2, ряд **477**. **Стратифицированный отбор** (ряд **449**) —
⛔ гейт `D39.50` НЕ снят: слово владельца дало санкцию на замер M4, а не разрешение строить; я исправил это в
трекере и плане сегодня. **N-4** и **Б-5** — ПОСТРОЕНЫ паком `D39.257`, заказом больше не являются. **N-6**
(журнал-телеметрия) — гейчен разморозкой фронта, ряды **214** и **221**. **N-5** — закрыт `D39.263`:
производитель — человек через сид. **Точечная перегенерация** (`D39.205` п.5) — банковый пак её не трогает, и
молчание здесь не отказ.
### 4.10. Стандарт работы — слово владельца, ратифицировано `D39.258` п.3
Чистый код, рефакторинг там, где он нужен, никаких заплаток, техдолга не копить. Мерило проекта —
**качество художественного перевода длинной книги**; механизм строится там, где несёт качество или деньги.
## 5. Самопроверка ИСПОЛНЕНИЕМ
Гейт зоны (`make battery`) обязателен и самопроверкой **не является**. Сверх него — адверсариальный проход по
своей готовой работе; субагентов поднимать разрешаю явно. Глубину выбираешь сама, направление даю я — пять мест,
где этот пак мягок:
1. **Потеря передачи у снятого кандидата** (§4.2) — самая тихая регрессия. Проверяй тем, что авто-банк и
стоп-таблица после прогона с базисом несут ТЕ ЖЕ ответы, что без него.
2. **Точка записи** (§4.3) — посадка, ставящая базис до развилки, обязана краснеть пином резюма.
3. **Отпечаток** (§4.4) — посадка, меняющая число или ширину окон, НЕ должна обнулять набор решённых.
4. **Первый резюм после записи базиса** — он платит за переупаковку хвоста один раз. ⛔ **Пин обязан различать ДВЕ
оси, и одну мою редакцию опровергатель снял как повторяющую ровно ту ложь, которую велит убрать ряд 448:**
(1) резюм ТОЙ ЖЕ покупки — $0 со второго; (2) СЛЕДУЮЩАЯ покупка, где решилась хоть одна новая строка, — хвост
батчей переупаковывается и платится снова. Вторая ось — та, ради которой пак существует («строка переживает
ПОКУПКУ»), и формулировка «каждый последующий прогон за $0» запрещена.
5. **`auto`-хвост** — строка, которую модель устойчиво считает не-термином, платится КАЖДУЮ покупку на
тождественном входе. Это цена, названная консилиумом; напечатай её числом.
**Мутации:** новые посадки вводи в гейт, иначе «поймана» — разовый прогон смены, а не рубеж проекта. Полный
прогон каталога после рефактора обязателен. ⛔ Гнать его **в переднем плане**: гейт движка не помещается в
фоновую задачу харнесса (ряд **488**), и это не про нехватку памяти машины.
## 6. Оси ревью
Две-три, можешь заменить с аргументом: **денежная** (ни один путь не покупает дважды и мимо бюджета) ·
**сохранность ответов** (ничего уже купленного не потеряно — §4.2) · **рефакторинг без регресса** (что переехало
и чем доказано, что поведение прежних вызывающих не изменилось).
## 7. Записка-план
До первой правки кода — короткая записка в свою секцию журнала: схема носителя и выбор его формы с доводом ·
форма отпечатка · таблица читателей ответа · что решила по юнитам (§4.5) · денежная семантика резюма.
## 8. Заявление = команда
Любое число и любая категорика отчёта идут **с командой, которой они получены**, — так, чтобы я повторил их у
себя, не переспрашивая. «Кампания зелёная», «мутации пойманы», «резюм бесплатен» без команды — утверждение О
проверке, а не проверка: читатель видит слово вместо числа. ⚠ Рядом с любым НУЛЁМ печатай контрольную величину,
доказывающую, что вопрос задан существующему предмету: «ноль строк» и «нет такой таблицы» в выводе неразличимы
и оба выглядят успехом. ⚠ Приёмка пере-ранит выборочно, и расхождение числа с его же командой дороже, чем
отсутствие числа.
## 9. Эхо-протокол старта
**Первым действием** — десять строк **своими словами**: скоуп, инварианты, чего не делаешь. Дословный пересказ
промта подтверждает канал, но не понимание.
## 10. Что не удалось — и где прибор слеп
Секция «не удалось / не проверено» обязательна. ⚠ И вторая половина: **«где мой прибор слеп и я это знаю»** —
что невидимо, почему не чинила, чем закрывается. Норма зоны: **в коде названо, в отчёте нет — значит для
следующей смены не названо.**
## 11. Канал вопросов, право отказа, советчик
Конфликт промта с кодом — **пинг**, не интерпретация: промт мог устареть между написанием и чтением, и за смену
это случалось. Право сказать «этого делать не надо» с аргументом у тебя есть, и два пункта этого пака я жду
скорее отказанными с замером, чем построенными наспех.
Тебе разрешён **один** старший советчик (`model: "fable"` явно) для развилки, которую не закрывает своё
суждение; досылай вопросы ему, а не поднимай новых — его контекст и есть ценность. Он советчик, не источник
истины: его посылки проверяются деревом. ⚠ Мой собственный советчик по этому паку дал девять замечаний, и
проверка деревом подтвердила не все: одно его предложение спорило с ратифицированным доводом в коде.
## 12. Прямой канал
Механизм — `CLAUDE.md` §«Связь между сессиями»; здесь он не повторяется, но **исполняется первым делом**: впиши
свой блок в `/tmp/textmachine-channel` (роль · имя из `ListAgents` · ссылка на ЭТОТ файл · дата · что делаешь и
чего не трогаешь), дописывая в конец и не трогая чужие блоки. Адрес оркестратора бери оттуда же, и туда же шли
эхо из блока 9 — оно и служит проверкой канала.
**Адрес из файла — НЕ доказательство, что сессия жива: файл переживает смерть сессии, а `ListAgents` — нет.**
⚠ **Нужной роли в файле нет, файла нет или имя не отвечает ⇒ КАНАЛА НЕТ, и это НОРМАЛЬНЫЙ случай: НЕ опрашивай
сессии подряд.** Вопрос — секцией в свой отчёт, работа продолжается; владелец прочитает и пере-передаст.
## 13. Критерий завершённости — проверяемый
- у **каждого** пункта заказа исход: сделано · не делаю с доводом · пинг;
- **числа блока 4.1 предъявлены и форма предиката принята мной** до того, как написан носитель;
- круги **сошлись**: последний не дал новых находок, прежние закрыты таблицей «находка → что сделано → **чем
предъявлено**»;
- таблица мутаций полная, выжившие названы поимённо, полный прогон каталога пройден;
- **список «что отрефакторено и почему»** — либо явное «рефакторинга не потребовалось» с доводом;
- числа сняты **после последней правки**, у каждого команда повторения; всё живое — **в дереве**;
- гейт зоны зелёный **целиком** (сверка списком целей, а не отсутствием слова FAIL);
- сказано явно: **«работа завершена, править не планирую»**.
## Приложение. Ряды, на которые пак опирается
Строит: **130** · **490**. Задевает и обязан назвать: **330** · **438** · **440** · **461** · **466** · **481** ·
**487**. Условия работы: **475** (купленные улики) · **488** (гейт в переднем плане) · **356** (пожизненный потолок).
**Ряд 478 — ЛАТЕНТНЫЙ, и называть его без оговорки нельзя** (поправка опровергателя): его посылка опровергнута
замером зоны 17.09 на настоящем батчере — снятие решённого кандидата даёт **0 сдвигов ординала из 246 снятий** при
положительном контроле 18 из 19, боевые конфиги размер батча не задают. ⇒ ключ покупки не трогать; перекупка первой
покупки после базиса идёт от смены СОДЕРЖИМОГО батча, а не ординала. Условие оживления класса — мелкий `batch_runes`.
**Две ноты 17.09 — условия работы твоего пака, и обе про деньги ровно тех ролей, которые он фильтрует.**
`D39.264` вынес петлю повторной попытки в общий контур и подключил банк-роли к вердикту; `D39.259` включил
`gates.terminology.regenerate: 1` во ВСЕХ трёх боевых конвейерах (`backend/configs/pipeline-c1.yaml:193`=`regenerate: 1`,
`backend/configs/pipeline-arm-glm.yaml:72`=`regenerate: 1`, `backend/configs/pipeline-arm-mistral.yaml:79`=`regenerate: 1`). ⇒ на батч возможна ВТОРАЯ платная ступень, и
промт обязывает тебя назвать: **чей ответ ложится в базис, если батч куплен лестницей** (ответ выигравшей ступени, не
первой) · не ломает ли базис посылку пина `backend/internal/pipeline/bankladder_test.go:111`=`func TestAHealthyBankTableIsNeverAskedAgain`
(«здоровая таблица покупается ровно раз»), чья посылка утверждается отдельной строкой —
`backend/internal/pipeline/bankladder_test.go:131`=`Gates.Terminology.Regenerate` — и без неё пин измерял бы ОТСУТСТВИЕ механизма,
о чём его докблок предупреждает сам · входит ли ступень в «$0 на резюме». Не входят, но названы: **447** · **448** · **449** · **477** · **214** · **221**.
⚠ Ряд **489** — ревизия документации твоей зоны, тринадцать дней без исполнителя: четыре пункта измерены живыми,
пять не измерены. Возьми в работу то, что дёшево, и назови остальное.