248 lines
27 KiB
Markdown
248 lines
27 KiB
Markdown
# Промт: бэкенд, пак «тихая порча» — книга уезжает неправильной, а тот, кто её читает, признака не видит
|
||
|
||
> **Выдан оркестратором №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` против рендера) — бюджет превышается на 40–60%. Та же
|
||
подсистема, что §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-путь или кеш». Находки в отчёт, включая отвергнутые с причиной.
|
||
⚠ **Веер: 2–4 агента, не больше.**
|
||
|
||
## §5. Оси ревью — 1–3, вправе заменить с аргументом
|
||
|
||
1. **Ось «что увидит читатель книги»** — не оператор и не тест: человек, купивший перевод.
|
||
2. **Ось «пара, которой в репо нет»** — правка не должна ветвиться по паре или книге (мандат
|
||
общности `CLAUDE.md`); ревью-вопрос: «заработает ли на паре, которой ещё нет, без правки Go».
|
||
3. **Ось «детерминизм»** — трогаешь сборку запроса: не сдвинулись ли снапшоты, версии и хеши так,
|
||
что прогон перекупается.
|
||
|
||
## §6. Записка-план, комплектность, «заявление = команда»
|
||
|
||
**До правок** — записка-план в своей секции журнала. **В конце** — таблица комплектности против §3:
|
||
пункт → что сделано → каким ИСПОЛНЕНИЕМ подтверждено. Слово вместо команды = пункт НЕ сделан.
|
||
|
||
## §7. Эхо-протокол старта — и проверка канала
|
||
|
||
ДО работы — ≤10 строк: **скоуп · инварианты · не-делать**. **Первое действие — вписать свой блок в файл канала (§10), сразу второе — послать мне эхо** по
|
||
адресу оттуда: я увижу понимание скоупа до работы, ты убедишься, что канал жив.
|
||
|
||
## §8. Obstacle — обязательная секция
|
||
|
||
**«Что НЕ удалось и что НЕ проверено»** отдельной секцией, не россыпью.
|
||
|
||
## §9. Канал вопросов и твоё право отказаться
|
||
|
||
Конфликт промта с кодом или доками — **пинг, не интерпретация в свою пользу**.
|
||
⚠ **У тебя есть право сказать «этого делать не надо» — с аргументом.** Промт писал не тот, кто живёт
|
||
в этом коде; сегодня ошибки находили в КАЖДОМ моём промте, в одном девять. Отказ с разбором дороже
|
||
послушного исполнения плохого пункта. Аддендумы доезжают ТОЛЬКО релеем через владельца.
|
||
⚠ **Тесты и гейты не подгонять под зелень.**
|
||
|
||
## §10. Как со мной связаться
|
||
|
||
**Адрес — в файле `/tmp/textmachine-channel`** (механизм — `CLAUDE.md`, «Связь между сессиями»).
|
||
**Впиши туда свой блок первым делом**, чужие не трогай. ⚠ **Канала нет ⇒ НЕ искать:** вопрос секцией
|
||
в отчёт, работа продолжается, владелец пере-передаст.
|