24 KiB
Промт: бэкенд, пак «тихая порча» — книга уезжает неправильной, а тот, кто её читает, признака не видит
Выдан оркестратором №19, 27.08.2026. Пак идёт ПАРАЛЛЕЛЬНО платформенному P9 (зоны не пересекаются). Оба его пункта гейчены одним событием — первым платным прогоном книги, — и это событие следующее в очереди проекта. Пока они открыты, платить за прогон значит платить за брак, который увидят не все и не сразу.
§0. Какая проблема и что решит твой результат
Продукт обещает две вещи: консистентные термины на всю книгу и честный текст на выходе. Сегодня оба обещания могут быть нарушены так, что человек, получивший результат, ничего не заметит.
1. Эскалация теряет банк памяти. Конвейер собирает ДВА системных сообщения — базовый промпт и
инъекцию банка (internal/pipeline/render.go:256 и :258). OpenAI-совместимый слой Gemini принимает
РОВНО ОДНО и лишние выбрасывает молча. Gemini стоит третьим хопом дефолтной цепочки боевого конфига
(configs/pipeline-c1.yaml:129). Итог: глава, доехавшая до этого хопа, переводится без канона
имён — то есть ровно без того, ради чего банк памяти существует. Носитель — строка 208.
⚠ Точность, без которой ты будешь чинить не то (нашла контрактная сессия). Дефект НЕ невидим
целиком: пост-чек глоссария работает ВСЕГДА (config/pipeline.go:445-452 — «ALWAYS runs…
converting silent glossary drift into a loud, visible signal») и меряет финал против того, что движок
СОБРАЛ (waverun.go:429 и :542, Postcheck(memSel.Injected, …)). Инъекцию выбросил сервер, а не
движок, — значит промахи конфирмятся и пишутся в retrieval-state. Дефект виден оператору
телеметрией и НЕвиден на проводе (postcheck_misses не в аллоулисте; гейт postcheck_gate в боевом
c1 отсутствует ⇒ дефолт false, ни флага, ни замечания). Пост-чек — НЕ лечение, он свидетель.
⚠ У дефекта ДВА пострадавших канала, а не один. Тем же вызовом собираются предложения терминов
для банкноты (waverun.go:363, sr.BankProposals — «the WHAT channel»). Хоп без канона генерит
предложения без контекста банка, они едут в карту подписи, и владелец подписывает из отравленного
списка. Цена дефекта удваивается. ⚠ И третье: :542 — это волна РЕДАКТОРА, то есть тот же хоп
молча съел бы правки владельца, доставленные вчерашней дверью (D39.161 обещает depth: refinement
— «правка доезжает до следующего прогона»).
2. Дыры выдачи молчат в САМОМ ТЕКСТЕ — и только в нём. Выпавший член юнита исчезает из
отгруженного текста без маркера: читатель получает склейку и признака в тексте не видит.
⚠ Формулировку сузила контрактная сессия, и сужение существенно: ПРОВОД признак несёт. Компаньон
контракта обещает различение дословно — «флаг+текст → translated с замечанием; флаг+пусто →
withheld», — то есть платформа и экран о замечании узнают. Слепа именно ВЫГРУЗКА: человек, который
получил файл с переводом, замечания не видит. Носитель — строка 193.
Что решит результат: после пака брак либо не возникает, либо ВИДЕН — и первый платный прогон можно покупать, не гадая, что он вернёт.
§1. Зона записи и git
Твоя зона — backend/. Итоги и находки — своя секция журнала docs/PROGRESS.md («Бэкенд»).
- Ты НЕ коммитишь. Лендит оркестратор после адверсариальной приёмки. Канон —
CLAUDE.md. - ⚠
platform/НЕ ТРОГАТЬ ВООБЩЕ: там прямо сейчас работает пак P9. Нужна правка на той стороне — это пинг, а не правка. docs/(кроме своей секции журнала),frontend/,eval/— не трогать. В дереве незакоммиченная работа полигона (20 позиций) — не касаться.
§2. Карта чтения — ≤5 позиций, ЗАКОН
docs/experiments/00-provider-quirks.md— ⚠ читать ПЕРВЫМ и ОБЯЗАТЕЛЬНО: это нормаCLAUDE.md(«провайдерские ловушки — читать ПЕРЕД правкой адаптеров и вызовов»). Твой пункт 1 — ровно правка адаптерного пути.- Сборка сообщений и провайдеры:
internal/pipeline/render.go:250-260(два системных) ·internal/llm/httpllm.go:513(toOpenAIMessages) ·internal/llm/provider_anthropic.go:145,163(у Anthropic системные — отдельные блоки сcache_control) ·internal/llm/capability.go(per-провайдерные квирки живут ЗДЕСЬ). - Конфиги:
configs/models.yaml:110(gemini через OpenAI-совместимый слой) ·configs/pipeline-c1.yaml:118-133(цепочка эскалации; ⚠ раннер исполняет SINGLE-HOP, и приbudget_usd=0эскалация не исполняется вовсе — достижимость зависит от конфига, см. §3.1). - Экспорт:
internal/pipeline/export.go— вокруг:211-230(c-lite: юнит флагается, когда член выпал) и:315-330(диспозиции иfinal_hash). docs/architecture/12-go-style-notes.md— норматив зоны, только больные места.
§3. Состав пака
§3.1. Инъекция банка не должна теряться — ЗАКАЗ; форма лечения СВОБОДНА
Заказано: после пака инъекция банка доезжает до модели на КАЖДОМ провайдере цепочки, либо вызов падает громко. Молчаливая потеря недопустима.
Свободен и обязан обосновать — ГДЕ лечить. Два очевидных места, оба со своей ценой:
- свернуть системные сообщения в одно прямо в
toOpenAIMessages— просто, но меняет провод ВСЕМ OpenAI-совместимым провайдерам, а не только тому, кто этого требует; - завести квирк в
capability.go(«принимает одно системное») и сворачивать только тем, у кого он стоит — точнее, но это новая ось в реестре возможностей.
Что знать, прежде чем выбирать (проверено мной, но пере-проверь):
toOpenAIMessagesкладёт сообщения ОДИН-В-ОДИН, сворачивания нет; её собственный комментарий говорит, чтоCacheBoundaryна этом пути бессмысленна (кеш префиксный и автоматический), и важен только ПОРЯДОК стабильного префикса — значит сворачивание кеш не портит;- у Anthropic путь другой: системные становятся отдельными блоками, а
CacheBoundary— реальнымcache_control. Сворачивать там нельзя, и правка не должна его задеть; - достижимость сегодня ограничена: раннер исполняет SINGLE-HOP, при
budget_usd=0эскалация не идёт. Дефект от этого не перестаёт быть дефектом — он ждёт первого конфига с бюджетом.
⚠ Второй вред, и он денежный. В день, когда включат postcheck_gate (задумано после E1),
потерянная инъекция превратит купленный эскалационный хоп — самый дорогой, апекс цепочки — в
flagged → withheld: заплатили за текст и выбросили его гейтом.
⚠ Норма проекта, исполнить буквально: поведение провайдера берётся из официальной документации вендора, а не из рассуждения. Клейм «принимает ровно одно системное сообщение» — пере-проверь по вендор-доке и приложи ссылку. Не подтвердилось — это находка, и пак меняется.
§3.2. Дыры выдачи обязаны быть ВИДНЫ — ЗАКАЗ; форма маркера СВОБОДНА
Заказано: отгруженный ТЕКСТ не может молча недосчитаться куска. Либо кусок на месте, либо его отсутствие видно ТОМУ, КТО ЧИТАЕТ ФАЙЛ. Форма свободна ровно в этих границах: маркер в тексте ЛИБО аннекс в самом отгружаемом файле. ⚠ Код выхода и сводка «где-то в отчёте» заказ НЕ закрывают — читателю файла они не видны никогда; прежняя редакция промта их предлагала, и это было противоречием собственному критерию (нашла контрактная сессия).
⛔ Жёсткое ограничение: маркер — ПРОЕКЦИЯ экспорта, а НЕ мутация финального текста в сторе. Две
причины, обе проверены: (а) вклеив маркер в текст юнита, ты превратишь флаг+пусто в флаг+текст, и
провод перечитает withheld как translated — сломается ровно обещание компаньона §2.7; (б)
сдвинется final_hash (stagerun.go:236) — то есть чекпойнты и перекупка волн. Безопасное место —
рендер выгрузки, и прецедент рядом: ApplyHeading (export.go:236) вклеивает титул именно там.
⚠ Классов дыр ТРИ, а строка 193 якорит один. Реши по каждому и обоснуй: (а) c-lite member-drop —
юнит теряет часть текста; (б) юнит целиком withheld — экспортится "", кусок отсутствует молча;
(в) gate-override glossary_miss — DispOK с подтверждённым промахом экспортится ""
(export.go:320-323).
⛔ АНТИ-скоуп: юнит, у которого санитайзер снял разметку, текст НЕ потерял — маркер на нём
дезинформирует читателя. Не помечать.
⚠ Язык маркера — это ДАННЫЕ пары, а не строка в Go. Словесный маркер едет на языке ЦЕЛИ, значит
его место в langpack (прецедент — heading.txt), либо маркер языконейтральный. Захардкоженная строка
одного языка формально «не ветвится по паре» и всё равно нарушает мандат общности CLAUDE.md.
⚠ Проверь прежде, чем строить: что из этого уже есть. Провод различение несёт (§0 п.2), и, может
статься, экспорт тоже несёт что-то, чего строка 193 не знает, — тогда пак сужается, и это находка.
⛔ Новых причин флага НЕ заводить. c-lite уже несёт причину первого выпавшего члена
(export.go:225-230); незнакомая причина по построению падает в unspecified на проводе — это
ратифицировано. Карта причин живёт в platform/internal/ingest/notes.go, а платформа заперта паком
P9, и положить туда новую причину НЕКУДА. Причины переиспользуй; если новая неизбежна — прими
unspecified и пингани. Мост между exit-контрактом и Note.code НЕ строить.
⚠ Якоря строки 193 подсохли — не верь им, грунтуй сам. Строка называет export.go:211-223 и
:324-329; я сверил — механизм c-lite действительно рядом (:227 и :320 ставят DispFlagged), но
второй якорь показывает ветку DispOK с громким отказом на пустой final_hash, а не то, что строка
обещает. Установи текущую правду сам — код первичен, строка бэклога вторична.
§3.3. ТРЕТИЙ пункт — идемпотентность, от которой зависит обещание канона
⛔ Добавлено 28.08 по находке воркфлоу-ревью платформы. Это НЕ «ещё один дефект» — это обещание, которое канон УЖЕ даёт на проводе, а движок не держит.
Канон 0.5.0 обещает дословно: «The remedy is to re-send the SAME document — the retry converges:
what already landed is recognised, not duplicated, and a fully-landed document answers 200 with
changed: false». На этом обещании стоит вся раскладка класса 15 («шли тот же документ»).
Движок его нарушает как минимум в одном случае (доказано исполнением через оракул репозитория):
decline поверхности ПОДПИСАННОГО сид-терма, у которой есть строка в дельте, — первый вызов принят,
повтор ТОГО ЖЕ документа отказывает. При частичной записи ре-сенд отбивается целиком, и
пользователь остаётся без пути вперёд: документ не применён, повторить нельзя.
Заказано: повтор принятого документа обязан сходиться — молча признавать применённое, а не
отказывать. Форма твоя. Проверь заодно родню из того же ревью: Д1 — decline не энтити-широк
на обратном пути (алиас возвращает отклонённую сущность, память глушит стоп навсегда); Д3 —
потеря маркера после стопа съедает оплаченный подписной стоп молча (гард LiftBankStop писан до
памяти предъявления v16). По каждой реши: чинить здесь либо строкой с причиной.
⚠ Почему здесь, а не «когда-нибудь». Смягчать канон я не стал: обещание правильное, дефект в
движке. Пока он открыт, деплой объявляет то, чего не держит — класс PD-370.
§3.4. Чего в паке НЕТ — пропуски подписаны
- Читающая сторона банка (строки 221/224/226) — форма разобрана консилиумом 27.08, но
её потребитель (экран подписи) ЗАМОРОЖЕН, и строить проекцию без живого потребителя значило бы
завести ровно тот класс дефекта, который назван в
18-bank-ontology.md. Ждёт заказа экрана. - Деньги банковых ролей (194, 197) — другая тема, гейчена следующим касанием денежного пути. Не бери попутно.
- Строка 198 (апгрейд стирает замечания) — нужна платформенная половина, а платформа занята P9.
§4. Самопроверка ИСПОЛНЕНИЕМ — «перечитал сам» её не удовлетворяет
- Батарея зоны под
-race, линтер 0 issues; числа — с командами. - Пункт 1 — тест обязан утверждать ПОСТ-ФИКСНЫЙ инвариант, а не наличие сообщений.
⛔ Прежняя редакция («покажи, что инъекция в запросе есть») была ВЫРОЖДЕННОЙ:
toOpenAIMessagesкладёт сообщения один-в-один, оба системных в запросе есть и СЕГОДНЯ — теряет их сервер. Такой тест зелен на непочиненном коде. Утверждать надо: у провайдера с квирком системное сообщение РОВНО ОДНО и инъекция внутри него; у Anthropic — два блока и живойcache_control. ⚠ И гонять ОБА пути — черновой (waverun.go:429) и РЕДАКТОРСКИЙ (:542): вчерашняя дверь правок доставляет владельческие правки именно вторым. Фейковый провайдер и харнесс $0 в репо есть, платных вызовов пак НЕ требует. ⚠ Дешёвый второй замер после фикса: кривая пост-чек-промахов на эскалационном хопе обязана упасть. - Пункт 2 доказывается ТЕКСТОМ: на ОДНОМ и том же состоянии с выпавшим членом покажи отгруженный текст до правки и после правки (не «до и после выпадения» — это другое). Разница и есть деливерабл.
- Свои посадки мутаций: минимум по одной на пункт; вердикт — по ДЕЛЬТЕ против чистой базовой линии и по ТОПИЧНОСТИ упавшего теста, не по цвету батареи.
Субагенты РАЗРЕШЕНЫ явно (иначе дефолт-запрет харнесса тихо побеждает). Опровергатель на выбор места лечения в §3.1 — ЗАКАЗ, не право: он получает оба варианта и мандат «покажи, где предложенное ломает Anthropic-путь или кеш». Находки в отчёт, включая отвергнутые с причиной. ⚠ Веер: 2–4 агента, не больше.
§5. Оси ревью — 1–3, вправе заменить с аргументом
- Ось «что увидит читатель книги» — не оператор и не тест: человек, купивший перевод.
- Ось «пара, которой в репо нет» — правка не должна ветвиться по паре или книге (мандат
общности
CLAUDE.md); ревью-вопрос: «заработает ли на паре, которой ещё нет, без правки Go». - Ось «детерминизм» — трогаешь сборку запроса: не сдвинулись ли снапшоты, версии и хеши так, что прогон перекупается.
§6. Записка-план, комплектность, «заявление = команда»
До правок — записка-план в своей секции журнала. В конце — таблица комплектности против §3: пункт → что сделано → каким ИСПОЛНЕНИЕМ подтверждено. Слово вместо команды = пункт НЕ сделан.
§7. Эхо-протокол старта — и проверка канала
ДО работы — ≤10 строк: скоуп · инварианты · не-делать. Первое действие — вписать свой блок в файл канала (§10), сразу второе — послать мне эхо по адресу оттуда: я увижу понимание скоупа до работы, ты убедишься, что канал жив.
§8. Obstacle — обязательная секция
«Что НЕ удалось и что НЕ проверено» отдельной секцией, не россыпью.
§9. Канал вопросов и твоё право отказаться
Конфликт промта с кодом или доками — пинг, не интерпретация в свою пользу. ⚠ У тебя есть право сказать «этого делать не надо» — с аргументом. Промт писал не тот, кто живёт в этом коде; сегодня ошибки находили в КАЖДОМ моём промте, в одном девять. Отказ с разбором дороже послушного исполнения плохого пункта. Аддендумы доезжают ТОЛЬКО релеем через владельца. ⚠ Тесты и гейты не подгонять под зелень.
§10. Как со мной связаться
Адрес — в файле /tmp/textmachine-channel (механизм — CLAUDE.md, «Связь между сессиями»).
Впиши туда свой блок первым делом, чужие не трогай. ⚠ Канала нет ⇒ НЕ искать: вопрос секцией
в отчёт, работа продолжается, владелец пере-передаст.