textmachine/docs/archive/prompts/BACKEND_SEAM_FIX2_SESSION_PROMPT_2026-08-27.md

61 KiB
Raw Permalink Blame History

Промт: БЭКЕНД ДОФИКС-2 «ВХОДНАЯ ДВЕРЬ ШВА» — флажок становится флажком, точка фиксации отчёта, фикс-лист приёмки

⚠⚠ ОТРАБОТАН И ЗАКРЫТ. Инструкции отсюда НЕ исполнять — файл сохранён как заказ, по которому судить исполнение.

Исход: пак входной двери шва исполнен и ПРИНЯТ 27.08 — ратификация D39.158, лендинг d1eb8a9. Дверь построена, стоп банка стал флажком, полоса отказов получила класс 15. ⚠ Якоря этого файла — на дерево ДО лендинга; часть из них лендинг сдвинул. Верить коду, не им.

Выдан оркестратором №19, 25.08.2026. Активный промт зоны бэкенда — один; этот заменяет BACKEND_SEAM_FIX_SESSION_PROMPT.md (отработан, уезжает в архив при лендинге). Параллельно законен только platform/docs/archive/PLATFORM_P8_REVIEW_SESSION_PROMPT_2026-08-22.md (ОТРАБОТАН 27.08) (read-only, пересечений нет).

1. Какая проблема и что решит твой результат

Продукт — издательский перевод больших книг мультиагентным пайплайном. Центральная ценность — банк памяти: сквозной глоссарий имён и терминов, держащий консистентность на всю книгу.

Две предыдущие сессии построили входную дверь: tmctl bank-apply принимает решения владельца данными, а не правкой YAML руками. Дофикс закрыл блокер формата и восемь мажоров. Приёмка прошла и снова не приняла — но главная её находка не в двери.

Продуктовая модель, ратифицирована D39.144 прямым словом владельца: стоп банка — это флажок. Опущен — прогон не останавливается, неподписанные строки едут редактору с пометкой. Поднят — полный останов, пользователь говорит «ОК», прогон продолжается. Пер-термной подписи в продукте нет: владелец подписывает банк целиком либо правит один термин, и правка — отдельная способность, доступная всегда, в том числе после перевода.

Движок этой модели не реализует. Стоп гаснет, только когда КАЖДАЯ предложенная поверхность промотирована или отклонена. Продукт ведёт себя правильно исключительно потому, что платформа снимает флаг при возобновлении своей персистентной колонкой.

Это НЕ новое открытие, и провенанс записан — прочти его прежде, чем проектировать. Формула «стоп гаснет, когда каждый терм промотирован или отклонён» родилась В ДВИЖКЕ 19.07 как лечение ливлока (отклонённый терм переспрашивался каждый прогон), то есть как условие выхода из паузы ОПЕРАТОРА CLI. Контрактная линия три недели спустя переписала её дословно и вывела продуктовое правило, которого никто не заказывал. D39.144 гейт сняла, но адресовала только КОНТРАКТ — движковая половина осталась без явной отмены и сегодня ОБОЙДЕНА, а не устранена. Носитель — строка бэклога 191(б), эррата — в шапке журнала решений (D39.153 п.7б).

Слово владельца 26.08, ПЯТЫЙ и решающий носитель: «стоп на банке памяти — это просто флажок. Юзер поднял флаг — полный останов до его ОК; опустил — перевод не останавливается. Всё». Канонизации в жесте «ОК» НЕТ: он значит «продолжай», а не «сделай предложенное каноном».

⚠⚠ И РАЗБЕРИСЬ С ОДНИМ ПРОТИВОРЕЧИЕМ ДО КОДА, иначе ты встанешь на нём по §11. Строка бэклога 191 говорит: «ОСТАТКА-РАТИФИКАЦИИ НЕТ… гейт проверяет полноту ФАЙЛА решений, а не подписей, и ОДИН файл со всем банком его снимает — конфликта с моделью владельца нет». Это не ошибка строки и не опровержение промта — она отвечала на ДРУГОЙ вопрос. Сверялось составное поведение: платформа снимает флаг, движок уходит по авто-ветке, зависания нет. Верно. Но её же живой остаток записан там дословно — «снять обход в платформе», — и снятие обхода возвращает границу паузы в несущие. Её пункт (б) заказывал «проверить/ослабить границу самой паузы»; исполнено было только «проверить». Ты делаешь отложенное «ослабить», и делаешь его в движке, потому что по п.1 закона поведение движка принадлежит движку, а не колонке чужой базы. Эррата к строкам 191 и 203(з) — на оркестраторе, при лендинге; тебе это знать, чтобы не встать.

Модель ПЕРЕ-ОПРЕДЕЛЕНА пятью носителями — не выводи её заново, ни из кода, ни из разговора. Нота D39.144 · продуктовый реестр docs/product-requirements.md, строка ПТ-24 («ОДИН ОК всему банку, не пер-термная масс-подпись») · экран банка во фронте, где прямо написано, что пер-термного состояния подписи на экране нет СОЗНАТЕЛЬНО и колонка «подписано» спорила бы с продуктом · надгробие снесённой ручки на платформе. Две сессии и два консилиума выводили её из кода и оба раза ошиблись.

И гардрейл оттуда же, ПТ-24, дословно: пост-ридинговые точечные правки с пере-генерацией по вхождениям — «механика после полигона». Значит не проектируй ничего про то, как правки работают ПОСЛЕ прочтения книги: ни глубины, ни отдельного цикла, ни новых полей под это. Смежный механизм точечной ре-редактуры уже существует и срабатывает на сдвиг банка — трогать его не надо.

Твой результат: флажок работает как флажок в самом движке, без участия чужой зоны, и вместе с этим закрывается точка фиксации отчёта, из-за отсутствия которой четыре раунда ревью подряд находили новую ветку одной дыры.

Дерево двух предыдущих паков НЕ закоммичено и лежит в рабочем каталоге. Ты продолжаешь его.

2. Зона записи и git

Пишешь ТОЛЬКО в backend/. Читать можешь всё; platform/, frontend/, eval/, docs/ — чужие зоны, правки в них запрещены. Единственное исключение: пинги и итог сессии — в docs/PROGRESS.md, секция «Бэкенд». Ты не коммитишь — дерево готовишь и передаёшь на лендинг оркестратору (канон git-норм — CLAUDE.md). git add -A, git add ., git commit -a запрещены в любом случае. В дереве живёт незакоммиченная работа параллельных сессий — не трогай её и не «прибирай».

3. Карта чтения (пять позиций)

  1. docs/architecture/05-decisions-log.md, нота D39.144 целиком, и эррата к ней в шапке журнала (D39.153 п.7б). Это ратифицированная модель и история вопроса. ⚠ Читать ДО кода: две сессии подряд восстанавливали этот провенанс из кода, потратив на это раунды.
  2. docs/PROGRESS.md, строка БЭКЛОГА 191 ⚠ ID строки ТАБЛИЦЫ, брать грепом ^| 191 |. Носитель темы, открытый ровно под твою работу.
  3. docs/architecture/17-seam-inbound-law.md — закон входной двери. П.1 («движок владеет своим поведением») — то, что сегодня нарушено.
  4. backend/docs/SEAM_PACK_FINDINGS.md — доказательная база двух паков. Вход — §26. ⚠ Секции 013 — улика первой приёмки, не трогай.
  5. docs/architecture/12-go-style-notes.md — норматив общности.

Код первичен. Все file:line ниже — отправные точки приёмки и сплошного чтения; проверяй сам.

4. Состав работы

Тринадцать пунктов (grep -cE '^### 4\.' → 13). §4.1§4.4 — семантика флажка, §4.5§4.8 — точка фиксации и полоса, §4.9§4.12 — фикс-лист. Комплектность сверяется механически (§7).

4.1 «Остановиться один раз» становится родным для движка — ДЕЛАЙ РОВНО ТАК инвариант, РЕШИ САМ форму

Движок заводит персистентную память «предъявленного стопом» — поверхности, за которые флаг уже заплатил остановкой. Стоп срабатывает, только если в текущем наборе есть поверхность вне запомненного. Предикат — «есть ли новое», не равенство наборов: равенство остановило бы снова на подмножестве уже виденного после первой же правки.

⚠⚠ Домен предиката задан жёстко, и промахнуться тут дорого. «Набор» — это содержимое КАРТЫ этого стопа, обе секции, ПОСЛЕ всех потолков; память — кластеры этого содержимого. Прочтение «набор = ранжированный пул ДО потолка» превращает флажок в ВЕЧНЫЙ стоп: постоянно невидимые за потолком поверхности (§4.4) делают «есть новое» истинным на каждом прогоне навсегда.

Проектные решения, каждое с доводом — они выведены сплошным чтением, не догадкой:

  • Ключ — нормализованная поверхность (text.NormalizeSourceKey, тот же, что у отказов и двери), а не пара (поверхность, перевод): предложенный перевод двигается от подписи СОСЕДНИХ термов (terminologist.go, ранжирование вариантов через approvedNeighbours), и память по паре дала бы вечные стопы.
  • Эмиссия работает КЛАСТЕРАМИ, а не поверхностями. Представитель кластера — первый в ранжированном пуле, и при росте книги он может смениться на алиас той же сущности. Память по одной поверхности этого не переживёт — лишний стоп на том же термине. Клади в память кластер (Src и Aliases, они уже посчитаны) и спрашивай про пересечение, а не про одну поверхность. ⚠ Остаток у кластерной памяти ДВУСТОРОННИЙ, и записать надо обе стороны, а не только удобную. Мягкая: сущность вернётся под написанием, которого в памяти нет — один лишний стоп, потерь нет. Вредная: подлинно НОВАЯ сущность, делящая поверхность-алиас с запомненным кластером (родной пример репозитория — одно прозвище на двух разных персонажей), пересечением пометится виденной и не будет предъявлена молча. Смягчено тем, что терм всё равно поедет редактору авто-строкой, но направление противоположное. Обе — ПРИНЯТЫЕ ОСТАТКИ, обе в отчёт.
  • Где живёт. Состояние КНИГИ, в store. ⚠ Прецеденты, которые я называл в прошлой редакции промта, прецедентами не являются, и я это снимаю: список отказов — ФАЙЛ рядом с книгой, а unitOnceKey живёт в events_outbox, который сам себя называет БУФЕРОМ, а не архивом, и чистится. Форму долговременного состояния книги выбираешь ты и аргументируешь.
  • Цена миграции названа заранее. Новая ТАБЛИЦА (CREATE TABLE IF NOT EXISTS) — дешёвая форма; ALTER существующей упирается в известный долг «шаги v8+ не идемпотентны» (строка 49а). Любая миграция двигает голову схемы, а OpenReadOnly отказывает при несовпадении — то есть все непере-мигрированные книги встают, и это ровно дедлок, который закрывали глаголом tmctl migrate. Порядок деплоя это покрывает, но в отчёте назови явно.
  • Книга без базы: отсутствие базы уже трактуется как «ничего не решено» — память унаследует «ничего не предъявлено», и это правильно.
  • Политика роста: НЕ обрезать. Память ⊆ намайненного словаря книги — тот же закон роста, что у списка отказов, который никто не обрезает. Без этой строки исполнитель изобретёт TTL и тем вернёт повторные стопы через заднюю дверь.

4.2 Порядок и момент записи — ДЕЛАЙ РОВНО ТАК

Сначала карта (атомарно), потом память. Падение между — лишний доброкачественный стоп на следующем прогоне; обратный порядок — поверхности помечены предъявленными, а карты нет: молчаливая потеря навсегда.

Это зависит от §4.10: карта сегодня пишется НЕ атомарно. Порядок работ не свободен — атомарность карты идёт первой.

⚠ Между картой (файл) и памятью (SQLite) общей транзакции нет. Реши явно и назови: валит ли отказ записи памяти уже состоявшийся стоп, или стоп остаётся, а память допишется на следующем.

Память пишется в момент СТОПА, не в момент «ОК». Тогда возобновление остаётся вызовом без полезной нагрузки, и нового глагола не нужно. ⚠ Никакого «подтверди карту» в дверь не заводить: согласия, которое надо якорить, в модели владельца не существует — это была ошибка приёмки, снята.

⚠ Ветка «только черновая волна»: карта пишется, стопа нет — памяти по букве тоже нет. Доброкачественно, но назови.

4.3 Авто-провод обязан работать при ПОДНЯТОМ флаге — ДЕЛАЙ РОВНО ТАК

Сегодня авто-провод закрыт условием «флаг НЕ поднят»: в этой ветке пишется авто-банк, пере-сидируется банк, обновляется экспорт. С поднятым флагом — ничего этого нет.

Сегодня не кусает только потому, что платформа флаг снимает. Ты этот сброс отменяешь — значит прогон с поднятым флагом, который НЕ остановился (нового нет), обязан идти дальше полноценно: записать авто-банк, пере-сидировать, обновить экспорт. Иначе «неподписанные строки едут редактору» отваливается ровно в том режиме, ради которого всё делается.

Перестрой ветвление так, чтобы решение «останавливаться ли» и решение «проводить ли неподписанное» были РАЗНЫМИ решениями. Сегодня это одно if.

⚠ И назови в записке ВТОРУЮ половину, которую этот пункт словами не покрывает: пишет ли авто-банк прогон, который ОСТАНОВИЛСЯ. Через чекпоинты терминолога сходится в обе стороны, поэтому решение должно быть НАЗВАННЫМ, а не случайным.

4.4 Хвост за потолком — НЕ ЛЕЧИТЬ, а честно назвать — ДЕЛАЙ РОВНО ТАК

Прежняя редакция этого промта заказывала фильтр карты как лекарство от голода. Заказ СНЯТ — он стоял на моей ошибке, и вот факт, который её опровергает.

Потолок эмиссии (200) применяется ДО фильтров пригодности, сида и отказов, а детектор кандидатов сида и отказов не видит вовсе. Репозиторий это про себя знает: «applied BEFORE the emission filters, so seed and declined terms do not free their slots». Замерено сплошным читателем на синтетическом корпусе: 2110 ранжированных, 442 годных во всём алфавите, 117 внутри окна потолка, 325 невидимы постоянно; отклонение всех 117 не подняло ни одного из 325.

Значит: хвост за потолком недостижим при любом решении владельца, и это верно СЕГОДНЯ, а не станет верным от твоей правки. Цитата про «пере-предлагается once these are signed or declined» относится к ОБРАТНОЙ секции, где фильтры действительно стоят до потолка.

Заказ: ничего не лечить. Назвать это в отчёте и пингом как отдельный предмет: «майнерский хвост за потолком структурно недостижим; двигать потолок — трогать фрозен-паритет, отдельное решение». ⚠ И не заводить фильтр карты «чтобы освободить хвост» — он не освободит, а сломает три вещи: карта пишется на КАЖДОМ прогоне до проверки флага; отказы фильтруются на общем списке, из которого кормятся и карта, и авто-банк, и кандидаты терминолога (ветки после него нет); а смена состава кандидатов промахивается мимо чекпоинтов терминолога и пере-оплачивает платную роль.

4.5 Единая точка фиксации отчёта — ДЕЛАЙ РОВНО ТАК инвариант, РЕШИ САМ форму

Класс, из-за которого четыре раунда ревью находили новую ветку одной дыры. Отчёт рождается до того, как исход вызова существует, и каждая ветка выхода правит свой кусок руками. Ветка отказа откатывает три поля предупреждения; ветка прерывания откатывает режим, флаг и список — и не откатывает signature, поэтому вызов, не записавший ни байта, печатает «не решено: 0». А ветка записи не правилась никогда: при отказе записи наружу уходит отчёт успешной формы. Приёмка это воспроизвела: EXIT=1, отчёт mode=apply changed=true, оба решения applied, на диске дельта записана, реджекты пусты.

Заказ — два движения, нужны оба:

(а) Разделить отчёт по природе полей. Вердикт о запросе (что принято, что отвергнуто и почему, индексы, replaced, preexisting, depth, files) — факт о решениях против состояния ДО; его на диске нет и не будет. Исход (режим, changed, предупреждения о пере-рендере, signature) — факт о мире ПОСЛЕ.

(б) Один конструктор на одном выходе. Эффектная фаза возвращает ЯВНОЕ значение исхода — проекция · отказ · no-op · прерывание · записано · запись не удалась — и единственная функция заполняет исходные поля свитчем по нему. Для «записано» пост-состояние — перечитанные файлы. Новая ветка тогда не сможет забыть поле: ей негде забывать. Пин — тест, перечисляющий исходы и проверяющий происхождение каждого поля.

⚠ Сильная форма «глагол вообще не сочиняет отчёт» НЕВЕРНА для вердиктной половины: причины отказов и история replaced на диске не лежат, и дверь потеряла бы собственный продукт.

4.6 signature.undecided пере-документируется, а не удаляется — ДЕЛАЙ РОВНО ТАК

Сегодня контракт поля говорит: «Undecided > 0 значит, что стоп НЕ погаснет, и это факт, не догадка». После §4.1 это ложь: стоп теперь зависит от памяти, а не от полноты решений. При этом канон понизил счётчик до информационного, а не до несуществующего — не удаляй.

Пере-документируй честно: что поле считает и чего оно больше не обещает. ⚠ И учти, что дверь открывает базу только на чтение — если ответ теперь требует памяти, реши, читает ли она её и на каком основании, или поле перестаёт отвечать на вопрос о стопе вовсе.

4.7 Полоса отказов получает два яруса — ДЕЛАЙ РОВНО ТАК

  • Пол полосы переформулируется из «ничего не произошло» в «нет работы, которую надо откатывать; повтор безопасен». «Повтор безопасен» = «не навредит», НЕ «поможет».
  • Каждый класс поверх пола объявляет свой, более сильный инвариант. Конфиг, источник, лок и отвергнутые решения сохраняют «ничего не произошло» как клаузу КЛАССА.
  • Гардрейл: разрушительное действие ключуется только на классе, никогда на принадлежности полосе. Сегодня истинно де-факто (проверено приёмкой) — становится буквой без миграции.
  • Один новый класс на «запись не завершена» — и для «не легло ничего», и для «легла половина»: потребитель ветвится одинаково, различие несёт пофайловый отчёт. Не сворачивать в класс конфига.
  • Класс отвергнутых решений однофóрмен: отказ по капу тоже печатает отчёт. Сегодня он печатает только строку в stderr, и контракт разошёлся между двумя своими носителями — свести к одному.

4.8 Подготовка обоих файлов, потом два переименования — ДЕЛАЙ РОВНО ТАК

Подготовить ОБА временных файла целиком (запись + синк), и только потом два переименования подряд. Тогда весь класс отказов среды ловится до первого сдвинутого байта, и репро §4.5 падает, ничего не записав.

Не заявляй шире сделанного: это атомарность против ошибок среды, не против смерти процесса — окно между переименованиями остаётся, и против SIGKILL атомарность пары требует журнала, механизма, которого дверь не заслужила. Остаток покрыт замеренной сходимостью (приёмка померила: повтор после половинной записи сходится и ПРАВИЛЬНО различает половины), а убитый процесс отчёта не печатает.

⚠ Отдельно: запись синкает файл перед переименованием, но не синкает КАТАЛОГ после. Файлы решений — слова пользователя: либо синк каталога, либо явная оговорка про долговечность.

4.9 Clean в резолве и конвенционные пути вместо ключей — ДЕЛАЙ РОВНО ТАК

(а) Попарная проверка путей сравнивает СТРОКИ, а резолв возвращает абсолютный путь без filepath.Clean. Приёмка обошла гард и воспроизвела исходный блокер целиком: два ключа на <dir>/shared.yaml и <dir>/./shared.yamlexit 0, оба решения applied, на диске только reject-лист, одобрение исчезло молча, следующий вызов включая --dry-run падает exit 10.

(б) Убрать оба ключа конфига: пути только конвенцией. Тогда путь есть функция от каталога и book_id, и межкнижная гонка недостижима по построению. Цена замерена: из 42 book.yaml ни один не объявляет читаемый путь, отличный от конвенции. Миграция громкая и дешёвая: строгий декодер уронит книгу с объявленным ключом, лечение — удалить две строки.

4.10 Карта подписи: атомарная запись и конверт — ДЕЛАЙ РОВНО ТАК

Карта пишется голым os.WriteFile в обход атомарной записи — единственный артефакт стопа без неё, при том что её читает другая сторона, а операционное правило платформы прямо говорит «на живом прогоне брать нельзя». С §4.2 это перестаёт быть гигиеной.

И у карты нет никакой идентичности — ни версии, ни хеша: единственный артефакт шва вне п.3 закона. Заведи конверт с версией и идентификатором, выведенным из СОДЕРЖИМОГО.

Карту не превращать в накопитель: комментарий в коде предупреждает, что слияние старой карты в новую изменило бы содержимое банка, сдвинуло версию памяти и пере-оценило редакторскую волну.

4.11 Слепые пятна гейта — ДЕЛАЙ РОВНО ТАК

Каждое — место, где приёмка посадила мутацию и батарея осталась зелёной; все пере-проверены во всех четырёх кандидатных пакетах пина.

что не сторожится мутация, которую пин обязан поймать
нормализация, суженная до одного триггера вместо класса normText: TrimSpaceTrimLeft(s, "\n")
субъект проблемы схлопывается до класса subjectOf возвращает только class
субъект теряет окно глав subjectOf без since/until
абсолютность путей в отчёте bank-apply (в статусе та же гарантия запинена) убрать приведение к абсолютному
границы обоих капов >>=
граница проверки перевёрнутого окна >>=, отвергает законное одноглавное окно

И самое неприятное: сегодня семантическое изменение §4.1 не краснит НИ ОДИН тест бэкенда. Это само по себе находка. Твой пак обязан завести пин, который краснеет от возврата к старой семантике, — иначе следующая сессия вернёт её молча.

4.12 Наследие отменённой модели — снести СПИСКОМ — ДЕЛАЙ РОВНО ТАК

⚠ Список, а не память сессии: починишь гейт и оставишь сообщение — следующий читатель движка выучит отменённую модель из его же слов.

  • Гейт «стоп гаснет от полного набора решений» — снимается §4.1.
  • Операторское сообщение стопа, дословно учащее «промотируй ИЛИ отклони КАЖДЫЙ терм, потом возобнови — стоп погаснет, когда решён каждый». Переписать под модель флажка.
  • Комментарии mining.go в шапке функции стопа и у unsignedEngineSurfaces; waverun.go; рендер CLI — сплошной читатель называет их поимённо, пройди по ним.
  • Новое состояние, которого раньше не было: «дельта непустая, нового нет». Сегодня флаг меняет лишь уровень лога на пустой дельте; теперь оператор с поднятым флагом может не получить ничего, и молчание будет неотличимо от «майнинг не сконфигурирован». Нужна явная строка.
  • Цепной тест TestTheStopClearsWhenTheOwnerDecidesTheWholeSignatureMap — ⚠ не удалять до §4.1 (подгонка зелени под доктрину). Он пройдёт и после §4.1, но по другой причине — потому что память погасит стоп, а не потому, что подписи что-то значат. Перепиши его под новую семантику и назови замену явно.
  • ПИНГИ ЧУЖИМ ЗОНАМ, не правки: у платформы умирает сброс флага, особый случай в спавне и персистентная колонка · во фронте и в полигоне есть потребители карты подписи, и смена её жанра их задела бы. Выпиши пингом в свою секцию журнала. ⚠⚠ И назови в пинге ПОРЯДОК, потому что опасная половина пишется легче. Сброс флага платформой может умереть ТОЛЬКО ПОСЛЕ того, как §4.3 залендится в движке. Обратный порядок — и в день лендинга каждая книга с поднятым флажком перестаёт писать авто-банк и пере-сидироваться ровно в том режиме, ради которого флажок существует. Порядок деплоя «движок первым» это обеспечивает, но зависимость обязана быть НАПИСАНА, а не выведена.
  • Миграционная нота: после апгрейда пустая память даёт один доброкачественный стоп. Назвать.

4.13 Деньги: платных вызовов НОЛЬ — ДЕЛАЙ РОВНО ТАК

Санкции нет и не запрашивается. Всё проверяется юнит-тестами, фейковым провайдером и пробой на копии книги стенда. Упёрся в место, где без денег не доказать, — пинг с названной суммой, не трата. Рантайм-вердикт по платному пути остаётся PLAUSIBLE.

Гипотеза о побочном выигрыше — НЕ выгода, пока не предъявлен механизм. Есть подозрение, что подписание сегодня промахивается мимо чекпоинтов терминолога и пере-оплачивает платную роль (ключ чекпоинта — хеш отрендеренных сообщений, а состав кандидатов меняется от дельты и отказов). Память предъявленного эти входы не трогает, поэтому «память чинит перерасход» механизмом не подтверждено и в отчёт как выигрыш идти не должно. Если увидишь механизм — покажи file:line; если перерасход существует сам по себе — это отдельный предмет и пинг, не твой заказ.

5. Мандат самопроверки ИСПОЛНЕНИЕМ

Не «перечитал» — исполнил. Минимум:

  • Батарея целиком, ИЗ КАТАЛОГА backend/, после каждой содержательной правки: go build ./..., go vet ./..., go test ./... -count=1, make lint. ⚠ go.mod в корне репозитория НЕТ. ⚠ И make battery-stand минимум один раз в конце. Ожидаемая картина: всё зелено, кроме парити на отсутствующем jieba-контрасте (вне git по построению, строка 123 — не твой дефект). Красный тест не «подгоняется»: править или удалять тест, голден или гейт ради зелени — НЕДОПУСТИМО. ⚠ В internal/store два пред-существующих -race-флейка, оба меряют ВРЕМЯ; приёмка доказала тремя путями, что они не от паков. Красное именно в них — шум.
  • Каталог мутаций расширяется: cmd/tmmutate + mutations.json несут 36 записей; каждая правка §4 обязана получить свою. ⚠ Инструмент честен — приёмка подсунула ему несобирающуюся посадку, он назвал её NOTHING, а не «поймано»; не сломай это свойство. ⚠ Посадка называет ПАКЕТ, в котором ищется пин, — не тот, где лежит правка.
  • Живая проба на копии книги стенда; в books/ не писать вовсе — чужой git-репозиторий.
  • Субагенты РАЗРЕШЕНЫ явно — на ревью своего кода, на поиск дефектов вне карты, на опровержение твоих же выводов. ⚠ Соразмеряй параллельность с ресурсами: агенты, одновременно гоняющие полную батарею, топят друг друга, а упавший от нагрузки выглядит как отсутствие находок.
  • Артефакт-находки обязателен: дописывай backend/docs/SEAM_PACK_FINDINGS.md новой секцией, не переписывая старые — они улика двух приёмок.

5.1 Обязательное для кодового пака

  • Последний абзац отчёта — план или обещание? Сделай его СЕЙЧАС.
  • Дифф ^func Test — исполнением.
  • Интервальная самоверификация субагентом против явных критериев в середине работы.
  • Перед отчётом сверь каждый клейм с результатом инструмента ЭТОЙ сессии.
  • Закрытие проверяется ОТДЕЛЬНО от починки и не тем, кто чинил. Предыдущая сессия вывела это правило сама: её собственная проверка закрытия нашла три незакрытых пункта из 28, а приёмка — ещё два частично закрытых, один из которых вернул исходный дефект.
  • И правило, которое стоило этому проекту трёх раундов подряд: прежде чем проектировать — прочти ратифицированное. Две сессии и два консилиума восстанавливали из кода то, что лежало записанным в журнале решений. Твоя карта чтения начинается с ноты не случайно.

6. Оси ревью (три)

  1. Семантика флажка — делает ли движок то, что описано в D39.144, без участия платформы. Проверяется прогоном движка напрямую, а не через её код.
  2. Единая точка фиксации — для каждой ветки выхода: откуда взято каждое поле отчёта, и может ли новая ветка забыть поле. Если может — конструктор не сделан.
  3. Слепота гейта — какой мутацией сторожится каждая правка и краснеет ли пин НА САМОМ ДЕЛЕ.

Ты вправе ЗАМЕНИТЬ любую ось своей с аргументом.

7. Записка-план

До кода — короткая записка backend/docs/SEAM_FIX2_PLAN.md: что делаешь, в каком порядке, какие развилки видишь. Комплектность против §4 сверяется МЕХАНИЧЕСКИ: grep -cE '^### 4\.' обязан дать 13, а не глазами.

Пак большой. Если считаешь, что семантика флажка (§4.1§4.4) и точка фиксации (§4.5§4.8) должны ехать разными паками — скажи это аргументом, это законный ответ по §11. Мой довод за один пак: обрамление отчёта умирает в обоих, и разделение повторило бы ровно ту патологию «починить одну ветку», из-за которой четыре раунда находили новую.

8. Заявление = команда

Каждое число и каждая категорика в отчёте — с командой, которой получены, прямо рядом. Приёмка пере-раняет выборочно.

ИСПОЛНЕНО ДО ТЕБЯ — только перепроверь, не делай заново. Довод к правке общего гейта в backend/Makefile называл 558 с на internal/pipeline под -race со словом «idle». Приёмка померила на свободном хосте 92.8 с в батарее и 97.6 с изолированно; автор прежнего числа назвал условия — его замер шёл под тремя параллельными сессиями, то есть неверно было слово «idle», а не факт. Сессия предыдущего пака переписала довод сама: теперь это ДИАПАЗОН с условиями обоих концов, без «idle», без привязки к машине и без процента от дефолта. Твоё дело — убедиться, что так и осталось, и не «улучшить» обратно в одно число.

Урок, ради которого это здесь: число без условий замера — не число. Оба замера были настоящими и расходились в шесть раз от одной только нагрузки.

9. Эхо-протокол старта

ДО работы — не больше десяти строк: скоуп как ты его понял · инварианты, которые не тронешь · что делать НЕ будешь.

10. Что НЕ удалось

Обязательная секция отчёта. «Не проверено» ≠ «работает». Вердикт о рантайме без живого прогона — максимум PLAUSIBLE.

11. Канал вопросов

Конфликт промта с кодом или доками — пинг через владельца, не интерпретация. Ты вправе сказать «этого делать не надо» с аргументом. §4.2, §4.4, §4.6 и §7 прямо приглашают такой ответ.


Приложение: что приёмка и сплошное чтение ПОДТВЕРДИЛИ — не чини заново

  • Блокер формата закрыт на уровне инварианта: round-trip держится на всех текстовых полях обоих документов на девяти неудобных значениях.
  • Каталог мутаций воспроизведён оркестратором: 36 посадок, 0 неожиданных исходов, дерево чистое.
  • Оба капа работают; цепь доходит до редакторской волны; батарея зелёная, линтер 0 issues; стенд-батарея красна ровно на парити.
  • Рукописные поля владельца переживают решение — род, тип, склонение с формами, алиасы, голоса.
  • Идемпотентность работает в отказе: после половинной записи повтор сходится и правильно различает половины.
  • Мины со снапшотом с этой стороны НЕТ: ни карта, ни таблицы, ни новая таблица store в версию памяти не входят — предупреждение в коде касается накопления в авто-банке.
  • Ключ по поверхности, а не по паре — подтверждён сплошным чтением с доводом сильнее исходного.
  • Отказы и память не дублируются: отказ гасит кластер и работает ещё на входе в банк и в обратной секции; память — только про стоп. Слить их нельзя: отклонённый терм поедет редактору.

Приложение: пинги, которые дофикс-2 НЕ исполняет

  • Майнерский хвост за потолком структурно недостижим (§4.4) — отдельный предмет.
  • Банк-экспорт на стопе ПУСТ (замерено сплошным читателем: total=0), при том что комментарий рядом называет стоп «границей, которую читает экран подписи», а машинную таблицу стопа не читает никто. Предмет платформенно-продуктовый, не твой.
  • exit 2 при нехватке памяти читается платформой как успешный прогон с флагами — общедвижковый класс.
  • readEngine платформы выбрасывает stdout при любом ненулевом коде, кроме 2 — требование к платформенному паку: отчёт при отказе И ЕСТЬ продукт вызова.
  • Развилка про канал ключей redrive · rubyToCandidates мёртв в проде · гейт диспетча слеп к case с константой · схема сида без omitempty — пинги прошлых паков, остаются пингами.
  • Проекция берёт тот же лок, что и применение — проектируется платформенным паком.

Записка от бэкенд-сессии двух предыдущих паков (написана до компакта её контекста, 27.08)

Я — сессия, которая строила дверь и оба дофикса. Дерево НЕ закоммичено, ты его продолжаешь. Здесь не инструкции — реонбординг: где что лежит, что я подтверждаю своим контекстом, на чём обжигался. Свежий взгляд с нуля ценнее моих планов, поэтому планов нет. ⚠ Прежняя моя записка (онбординг в формат и историю) живёт в хвосте BACKEND_SEAM_FIX_SESSION_PROMPT.md и уедет в архив — несущее повторено здесь.

Реонбординг в код — обе точки входа разобраны на ИМЕНОВАННЫЕ фазы, и это твой рычаг

  • internal/membank/decisions.go — чистая семантика. ApplyDecisions = resolveAllrefuseSeedConflictsfoldAcceptedrefuseInertDeclinesrefuseNewFaults; мутирует РОВНО одна фаза (foldAccepted), остальные судят. Прочитать пять имён = прочитать контракт двери.
  • internal/pipeline/bankdecisions.go — обвязка: openDecisionRequest → лок → readBookStateApplyDecisionsdecisionReportchangedFileswriteDecisionFiles. §4.5 садится ровно сюда: отчёт рождается в decisionReport ДО исхода, и каждая ветка выхода после неё правит поля руками. Подтверждаю оба репро приёмки из своего контекста — это мои недочинки: stopped-ветка чинит mode/changed/accepted и НЕ трогает signature (он считается в signatureState, поле unreadable там уже есть — пригодится в §4.6); ветка отказа записи не правилась никогда.
  • §4.1§4.3 живут в internal/pipeline/mining.go: runBankMiningStop — стоп и авто-провод сегодня действительно одно if !r.VerifyBank; рядом unsignedEngineSurfaces (фильтр «подписанного»), ownerHandled, rejectSurfaces, signatureMapPath (есть и пакетный помощник, не только метод). Store: internal/store/store.go, схема v15, tmctl migrate есть, LockProject/OpenReadOnly готовы.
  • Карта «предмет → пин»: membank/decisions_test.go (семантика) · decisions_fuzz_test.go (round-trip, три фаззера) · pipeline/bankdecisions_test.go (обвязка, классы, стоп-путь) · bankchain_test.go (цепь; НАМЕРЕННО писан под старую семантику — §4.12 велит переписать; сохрани его премисс-проверки, фикстура даёт ровно «2 терма = 1 approve + 1 decline») · statusartifacts_test.go · config/decisionpaths_test.go · cmd/tmctl/keysfile_test.go.

Инструмент, без которого не сдавай

cmd/tmmutate: -root ОБЯЗАТЕЛЕН и это должна быть КОПИЯ (cp -a backend /scratch/x && cd /scratch/x && go run ./cmd/tmmutate -root .). 36 записей, три вердикта (RED / NOTHING / survives), зелёная база пакета ДО первой посадки. ⚠ Якоря записей — точные строки кода: твой рефакторинг их сдвинет, инструмент скажет громко — пере-указывай сразу, это нормально. Со мной это однажды случилось МОЛЧА (старая версия считала провал сборки красным, и две записи целую итерацию числились пойманными тестами, которые не могли отработать) — теперь NOTHING роняет гейт; промт прав, что это свойство ломать нельзя.

Ловушки, каждая стоила мне прогона

  1. Живая проба на стенде: копия ВНЕ дерева; мёртвые абсолютные пути в ТРЁХ файлах (book.yaml, pipeline.yaml и pairs/zh-ru.yaml — в последнем prompts_root, про него забываешь); база схемы v11 → tmctl migrate на копии; банк-стоп на этой машине НЕ воспроизводится (нет jieba-контраста) — для стопа и цепи бери харнесс miningstop_join_test.go, он $0 и уже гоняет всё это. ⚠ К §4.9(б): стендовые book.yaml объявляют оба ключа — в КОПИИ удали эти две строки сам; на самом стенде это не твоя зона (пинг оркестратору отправлен, он в курсе).
  2. Батарея: полная на ненагруженной машине зелёная ЦЕЛИКОМ; два store-флейка изолированно через -run падают детерминированно на обеих сторонах A/B (сжатый opTimeout) — не отнеси на себя. Числа времени под нагрузкой параллельных сессий гуляют в 36 раз — не публикуй ни одного времени без пометки, была ли нагрузка (я на этом попался дважды: §8 промта — про меня).
  3. Субагенты и копии пишут туда, куда смотрят: перед каждым «финальным» прогоном — git ls-files --others и сверка sha256 копии с деревом.

Правила, купленные тремя раундами ревью подряд — они теперь и в §5.1, но вот цена

  • Закрытие проверяет НЕ тот, кто чинил. Моя собственная проверка закрытия нашла 3 незакрытых и 7 частичных из 28 «исправленных»; ни одно моё «всё исправлено» за сессию не выдержало проверки.
  • Сначала посадка, потом пин. Дважды поймало ВАКУУМНЫЕ пины моего же авторства (пин, написанный первым, проверяет то, что и так верно).
  • Худшие мои дефекты были НЕВЕРНЫМИ ДОВОДАМИ при верном коде — комментарий здесь контракт, по которому следующая сессия действует. Довод без команды хуже отсутствия довода.

Подтверждения, чтобы ты не тратил раунд на пере-открытие

  • Репро §4.5 и §4.9(а) — честные, не оспаривай, воспроизводи и чини.
  • «Семантика §4.1 не краснит ни один тест» — правдоподобно и по моему знанию тестов: всё, что я запинил про стоп, запинено через РЕЗУЛЬТАТ двери, не через условие гашения.
  • FINDINGS: вход через §26; §§013 — улика первой приёмки, §§1435 — мои; дописывай НОВЫМИ секциями.
  • Каталог мутаций: запись G-byte-gate — записанный ВЫЖИВШИЙ с доводом недостижимости; не «чини» её.
  • Обмен с оркестратором закрыт (прямой канал, 27.08), четыре факта оттуда: (1) ратификация нового класса полосы «запись не завершена» — НА НЁМ, тем же лендинг-актом, что эрраты к 191/203(з); тебе — только движковая сторона (значение, номер, один класс на оба исхода с пофайловой правдой в отчёте); (2) стендовые book.yaml с ключами снимает он/владелец — не твоя зона; его замер «42 файла, ЧИТАЕМЫХ отклонений от конвенции ноль» сходится с моим; (3) заказ §8 УЖЕ ИСПОЛНЕН мной до компакта: слово idle в Makefile было неверным (мой замер шёл под тремя параллельными сессиями), довод переписан на диапазон ~95 с (свободный хост) … ~560 с (три сессии) без привязки к машине; ложное «на незагруженной машине» в FINDINGS §31 тоже исправлено — НЕ делай этот пункт заново, только перепроверь; (4) ⚠ отчёт сплошного читателя, на котором стоит §4.4 (2110/442/117/325), в репозиторий не попал — числа промта без первоисточника в дереве; будешь на них опираться — пере-мерь сам, это признал сам оркестратор.

— бэкенд-сессия паков, до компакта