textmachine/docs/BACKEND_SILENT_HARM_SESSION_PROMPT.md

248 lines
27 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.

# Промт: бэкенд, пак «тихая порча» — книга уезжает неправильной, а тот, кто её читает, признака не видит
> **Выдан оркестратором №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 позиций, ЗАКОН
1. **`docs/experiments/00-provider-quirks.md`** — ⚠ **читать ПЕРВЫМ и ОБЯЗАТЕЛЬНО: это норма
`CLAUDE.md`** («провайдерские ловушки — читать ПЕРЕД правкой адаптеров и вызовов»). Твой пункт 1 —
ровно правка адаптерного пути.
2. **Сборка сообщений и провайдеры:** `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-провайдерные квирки живут ЗДЕСЬ).
3. **Конфиги:** `configs/models.yaml:110` (gemini через OpenAI-совместимый слой) ·
`configs/pipeline-c1.yaml:118-133` (цепочка эскалации; ⚠ раннер исполняет SINGLE-HOP, и при
`budget_usd=0` эскалация не исполняется вовсе — достижимость зависит от конфига, см. §3.1).
4. **Экспорт:** `internal/pipeline/export.go` — вокруг `:211-230` (c-lite: юнит флагается, когда член
выпал) и `:315-330` (диспозиции и `final_hash`).
5. **`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. Дыры выдачи обязаны быть ВИДНЫ — ЗАКАЗ; форма маркера СВОБОДНА
**Заказано:** отгруженный ТЕКСТ не может молча недосчитаться куска. Либо кусок на месте, либо его
отсутствие видно ТОМУ, КТО ЧИТАЕТ ФАЙЛ. **Форма свободна ровно в этих границах: маркер в тексте ЛИБО
аннекс в самом отгружаемом файле.** ⚠ Код выхода и сводка «где-то в отчёте» заказ НЕ закрывают —
читателю файла они не видны никогда; прежняя редакция промта их предлагала, и это было противоречием
собственному критерию (нашла контрактная сессия).
**СТОЛКНОВЕНИЕ, знать ДО выбора места (строка 201).** В ту же функцию экспорта уже вклеивается
детерминированное «Глава N» — `export.go:231`, «Title policy (pack-13)» — и это движковый текст,
доезжающий читателю ВНУТРИ экспорта в обход дисциплины `heading: null`. **Не строй второй обходной
путь рядом с первым:** либо твой маркер встаёт тем же механизмом и там же, либо ты объясняешь, почему
ему нужно другое. Саму строку 201 при этом НЕ чини — она не заказана.
**Жёсткое ограничение: маркер — ПРОЕКЦИЯ экспорта, а НЕ мутация финального текста в сторе.** Две
причины, обе проверены: (а) вклеив маркер в текст юнита, ты превратишь `флаг+пусто` в `флаг+текст`, и
провод перечитает `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`).
**ЧЕТВЁРТЫЙ случай той же поверхности — строка 141, и у него ГРАНИЦА.** Сноска вида «[1] …» без
слова-заголовка проходит мимо детектора примечаний (`internal/checks/sanitizer.go` — детект требует
«Примечание:/прим. перев.»), и после снятия ханьцзы текст уезжает в экспорт **с дырой на месте
вырезанного**. Читатель тот же, файл тот же, способ не заметить тот же.
**Границу соблюдай буквально:** накрывает ли его механизм маркера из этого же заказа — **бери, это
бесплатно**. Требует работы в самом ДЕТЕКТОРЕ — **не бери**, назови строкой и оставь: это отдельный
предмет, и пак не должен из-за него распухнуть.
**АНТИ-скоуп:** юнит, у которого санитайзер снял разметку, текст НЕ потерял — маркер на нём
**дезинформирует** читателя. Не помечать.
**Язык маркера — это ДАННЫЕ пары, а не строка в 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**) — другая тема, гейчена следующим касанием денежного
пути. Не бери попутно.
- **Строка 131 — СОСЕД, не заказ.** Кап инъекции считает только «src → dst» и не считает маркер и
родовые пометки (`membank/memory.go:511-518` против рендера) — бюджет превышается на 4060%. Та же
подсистема, что §3.1, и ты будешь в этом коде; но тема другая — деньги и качество инъекции, а не
молчаливый брак в тексте. Увидишь — не чини, скажи.
- **Строка 198** (апгрейд стирает замечания) — нужна платформенная половина, а платформа занята P9.
## §4. Самопроверка ИСПОЛНЕНИЕМ — «перечитал сам» её не удовлетворяет
1. **Батарея зоны** под `-race`, линтер 0 issues; числа — с командами.
2. **Пункт 1 — тест обязан утверждать ПОСТ-ФИКСНЫЙ инвариант, а не наличие сообщений.**
⛔ Прежняя редакция («покажи, что инъекция в запросе есть») была ВЫРОЖДЕННОЙ: `toOpenAIMessages`
кладёт сообщения один-в-один, оба системных в запросе есть и СЕГОДНЯ — теряет их сервер. Такой
тест зелен на непочиненном коде. Утверждать надо: **у провайдера с квирком системное сообщение
РОВНО ОДНО и инъекция внутри него; у Anthropic — два блока и живой `cache_control`.**
⚠ И гонять ОБА пути — черновой (`waverun.go:429`) и РЕДАКТОРСКИЙ (`:542`): вчерашняя дверь правок
доставляет владельческие правки именно вторым. Фейковый провайдер и харнесс $0 в репо есть,
платных вызовов пак НЕ требует.
⚠ Дешёвый второй замер после фикса: кривая пост-чек-промахов на эскалационном хопе обязана упасть.
3. **Пункт 2 доказывается ТЕКСТОМ:** на ОДНОМ и том же состоянии с выпавшим членом покажи отгруженный
текст **до правки и после правки** (не «до и после выпадения» — это другое). Разница и есть
деливерабл.
4. **Свои посадки мутаций:** минимум по одной на пункт; вердикт — по ДЕЛЬТЕ против чистой базовой
линии и по ТОПИЧНОСТИ упавшего теста, не по цвету батареи.
**Субагенты РАЗРЕШЕНЫ явно** (иначе дефолт-запрет харнесса тихо побеждает). **Опровергатель на выбор
места лечения в §3.1 — ЗАКАЗ, не право:** он получает оба варианта и мандат «покажи, где предложенное
ломает Anthropic-путь или кеш». Находки в отчёт, включая отвергнутые с причиной.
**Веер: 24 агента, не больше.**
## §5. Оси ревью — 13, вправе заменить с аргументом
1. **Ось «что увидит читатель книги»** — не оператор и не тест: человек, купивший перевод.
2. **Ось «пара, которой в репо нет»** — правка не должна ветвиться по паре или книге (мандат
общности `CLAUDE.md`); ревью-вопрос: «заработает ли на паре, которой ещё нет, без правки Go».
3. **Ось «детерминизм»** — трогаешь сборку запроса: не сдвинулись ли снапшоты, версии и хеши так,
что прогон перекупается.
## §6. Записка-план, комплектность, «заявление = команда»
**До правок** — записка-план в своей секции журнала. **В конце** — таблица комплектности против §3:
пункт → что сделано → каким ИСПОЛНЕНИЕМ подтверждено. Слово вместо команды = пункт НЕ сделан.
## §7. Эхо-протокол старта — и проверка канала
ДО работы — ≤10 строк: **скоуп · инварианты · не-делать**. **Первое действие — вписать свой блок в файл канала (§10), сразу второе — послать мне эхо** по
адресу оттуда: я увижу понимание скоупа до работы, ты убедишься, что канал жив.
## §8. Obstacle — обязательная секция
**«Что НЕ удалось и что НЕ проверено»** отдельной секцией, не россыпью.
## §9. Канал вопросов и твоё право отказаться
Конфликт промта с кодом или доками — **пинг, не интерпретация в свою пользу**.
**У тебя есть право сказать «этого делать не надо» — с аргументом.** Промт писал не тот, кто живёт
в этом коде; сегодня ошибки находили в КАЖДОМ моём промте, в одном девять. Отказ с разбором дороже
послушного исполнения плохого пункта. Аддендумы доезжают ТОЛЬКО релеем через владельца.
**Тесты и гейты не подгонять под зелень.**
## §10. Как со мной связаться
**Адрес — в файле `/tmp/textmachine-channel`** (механизм — `CLAUDE.md`, «Связь между сессиями»).
**Впиши туда свой блок первым делом**, чужие не трогай. ⚠ **Канала нет ⇒ НЕ искать:** вопрос секцией
в отчёт, работа продолжается, владелец пере-передаст.