textmachine/docs/BACKEND_MONEYSTOP_SESSION_PROMPT.md

194 lines
23 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.

# Промт сессии: БЭКЕНД — «денежный стоп перестаёт быть аварией»
> **Роль:** бэкенд. **Зона записи:** `backend/` + СВОЯ секция в `docs/PROGRESS.md`. Чужие зоны
> (`platform/`, `frontend/`, `eval/`) читаешь, не правишь. **Не коммитишь** и вообще не трогаешь индекс
> и историю — почему именно и полный список запретов: `CLAUDE.md`, §«Git-координация мультисессий».
> Дерево готовишь и передаёшь оркестратору на лендинг.
## 1. Какая проблема и что решит твой результат
Пользователь покупает перевод книги. Сегодня **книгу нельзя дочитать никакими деньгами**, а книга
короче десяти глав не переводится вообще никогда. Замерено живьём на платном прогоне и воспроизведено
дважды. Половина причины — платформенная (форма потолка), и её чинит другой пак. **Твоя половина —
движковая, и она гейт: пока она не сделана, любая новая форма заказа упирается в ту же стену.**
Механизм: движок резервирует оценку перед каждым вызовом и **отказ ОДНОГО резерва гасит всю книгу**
уже допущенные параллельные вызовы отменяются, ничего не списывается, ничего не производится. Прогон
умирает за 1015 секунд с нулём сделанного.
**Результат, которого ждут:** отказ в резервации означает «не начинаем новое», а не «убиваем начатое».
Прогон доводит допущенное, завершается штатно и НАЗЫВАЕТ, сколько не хватило.
## 2. Зона записи и git
См. шапку. Дополнительно: `docs/architecture/**` — зона оркестратора, туда не пишешь; расхождение
дока с кодом — пингом в свою секцию `docs/PROGRESS.md`, не своей правкой.
## 3. Карта чтения — ПЯТЬ позиций, дальше только по ссылкам отсюда
1. `docs/architecture/05-decisions-log.md`, нота **`D39.196`** — РАТИФИЦИРОВАННАЯ форма заказа, ради которой
этот пак и есть гейт; затем `docs/architecture/15-money-path.md` §«ОТКРЫТАЯ РАЗВИЛКА 04.09» — разбор, из
которого решение выросло (все числа с носителями). ⚠ Читать в этом порядке: разбор без ноты читается как
открытый вопрос.
2. `docs/PROGRESS.md`, строки бэклога **277 · 278** — твой состав, формулировки зоны.
**Строки 261 и 262 в ЭТОТ пак НЕ входят** — они назначены дофиксу, который прямо сейчас доделывает ДРУГАЯ сессия зоны
(эррата 04.09-д: «зона чинит и держит сдачу; строки 256264 закрываются её лендингом»). Две сессии в одном `stagerun.go`
это конфликт, а не параллельность. ⚠ Если к твоему старту дофикс уже заленджен — спроси оркестратора пингом, брать ли их;
сам не бери.
3. `backend/internal/pipeline/volume.go`, греп `THE STOP IS A COMPLETION, NOT A HALT` — **прецедент
внутри твоего же пакета**: объёмный потолок уже построен с нужной семантикой и САМ противопоставляет
себя денежному.
4. `docs/architecture/05-decisions-log.md` — грепом: `D39.122` (семантика `--ceiling-usd`), `D39.170`
(структурное лечение пробоя потолка), `D39.183` (правка тестов — про МОТИВ).
5. `docs/experiments/00-provider-quirks.md`**перед любым утверждением о биллинге провайдера.**
**Код первичен.** Отправные точки, а не истина: `stagerun.go` (греп `r.Store.Reserve(r.Book.BookID`,
`ReserveDeniedBook`, `No 2xx ever arrived`), `waverun.go` (греп `context.WithCancel`), `ledger.go`
(греп `func (s *Store) Reserve`), `httpllm.go` (греп `for att := 0; att < profile.MaxAttempts`).
## 4. Состав — что делать РОВНО так и что решаешь сам
**(1) ДЕЛАЙ РОВНО ТАК — ПЕРВЫМ, строка 271: правки банка пользователя едут в SYSTEM-сообщение ДОСЛОВНО.**
Тело собирается конкатенацией `src + " → " + dst`, `dst` приходит с пользовательской двери и получает
ровно один `TrimSpace`; предела длины нет, управляющие символы не запрещены. ⇒ `dst` с переводами
строки дописывает свои строки внутрь системного блока КАЖДОГО платного вызова. ⚠ Ратифицированный инвариант проекта (**D25**, фактура — `docs/research/17-external-critique.md` §A10.2) требует, чтобы текст
книги и любая внешняя выдача были ДАННЫМИ, а не инструкциями, и до сих пор это держалось САМОЙ КОНСТРУКЦИЕЙ — писать в
промпт было некому. Теперь есть: появилась пользовательская запись, открывающаяся в system-роль. ⚠ Формулировку в кавычках
не ищи — её нет, это пересказ; ссылайся на ноту и ресёрч. Лечение: предел длины, запрет управляющих, обрамление как ДАННЫХ.
⛔ **АРТЕФАКТ ПРИЁМКИ НАЗВАН: тест батареи, в котором `dst` несёт переводы строк и текст, похожий на системную инструкцию,
и он предъявлен КРАСНЫМ до починки и зелёным после.** Плюс посадка в каталог `tmmutate`: снятие предела длины ИЛИ снятие
запрета управляющих обязано краснеть. Без этих двух пункт не сдан.
⚠ Это обязано быть закрыто ДО того, как внутрь пустят первого внешнего человека, — а платформенный
пак, который его пускает, идёт ПАРАЛЛЕЛЬНО твоему.
**ПОЧЕМУ ПЕРВЫМ, а не райдером:** это ЕДИНСТВЕННЫЙ пункт пака, который реально гейтит «можно ли пускать человека», и он
дешевле остальных. В первой редакции он стоял четвёртым, райдером после трёх денежных пунктов — след того, что состав
вырос из денежного разбора, а не из чтения бэклога. Порядок исправлен 05.09; сессия читает первым то, что первым и надо.
**(2) ДЕЛАЙ РОВНО ТАК — отказ резерва перестаёт гасить допущенное.** Отступление = пинг.
· Отказ **защёлкивается на уровне ВОЛНЫ**: кормилец перестаёт раздавать индексы по первому
`ReserveDeniedBook`. Без защёлки W воркеров дадут W путей ошибки вместо одной остановки.
· Уже допущенные вызовы **дорабатываются**. `cancel()` по деньгам не зовётся.
· При непустом полёте отказ **не окончателен**: ждать settle (settle ≤ оценки, значит запас растёт) и
повторить тот же резерв. Отказ при пустом полёте — стоп.
· Завершение **штатное**, с леджером сделанного и отложенного. Exit 4 и `paused` остаются: семантика
«деньги кончились, резюмируемо» верна.
**(3) ДЕЛАЙ РОВНО ТАК — «сколько не хватило» доезжает наружу.** Число у тебя уже есть и печатается
(`denied estimate=$…`), но умирает в stderr транзиентного юнита. Оно обязано ехать в событие `ceiling`
отдельным полем. ⚠ Наружу — только НЕДОСТАЮЩАЯ сумма; цены моделей, стадий и вызовов не выходят.
**(4) ДЕЛАЙ РОВНО ТАК — проекция цены в `manifest --json` и `status --json`.** По ЮНИТУ: `source_chars`
(руны ингестированного текста, включая пробелы), раздельно плотные/разреженные знаки, `expected_usd`;
по КНИГЕ: `book_once_usd` (книжное слагаемое — терминология тратится на книгу, не на юнит) и
`step_max_usd` (самый крупный неделимый резерв). Считается из СВОИХ цен и фертильности, **без константы
за главу**. Плюс `structure: detected|declared|none` — признак доверия к нарезке. Всё аддитивно, версию
манифеста НЕ двигает.
**РЕШАЕШЬ САМ И АРГУМЕНТИРУЕШЬ (промт форму НЕ задаёт):** как считается `expected_usd` — по
отрендеренному промпту с инъекциями или по сырому тексту, какие стадии входят, учитывать ли ретраи и
эскалации; по какому признаку выставляется `structure: detected|declared|none`; какую форму имеет
леджер сделанного и отложенного в `finished`. Каждый выбор — с доводом в отчёте.
**(5) РЕШАЕШЬ САМ И АРГУМЕНТИРУЕШЬ:** форма защёлки; где именно ждать settle; как назвать поля;
сеттлить ли оценкой поздно отменённый вызов и по какому различителю (латентность — кандидат, порог
обязан быть обоснован ЗАМЕРОМ, а не назначен).
**(6) НЕ ДЕЛАЙ:** не убирай резервацию — она единственная гарантия «не потратим больше, чем дано»;
не резервируй «ожидаемое» вместо worst-case; не ужимай `max_tokens` под остаток (двигает `request_hash`
⇒ снапшот и детерминизм, и даёт `finish=length` ценой целой генерации); не трогай кумулятивную
семантику `--ceiling-usd`; не двигай `manifestVersion`, схему и контракт. ⚠ **`StreamVersion` — ИСКЛЮЧЕНИЕ и его двигать НАДО:** добавление поля в кадр — минорный бамп по правилу шва (`internal/runevents/runevents.go`, греп `IT WAS ALMOST NOT BUMPED` — там записана ровно эта ловушка). Прежняя редакция промта запрещала бамп и заказывала поле одновременно; противоречие снято 05.09.
## 4-бис. ЧЕСТНО О ПРОИСХОЖДЕНИИ СОСТАВА И ЧТО В ПАК НЕ ВОШЛО
**Честно о происхождении состава:** пункты 13 выше выведены из денежного разбора, а не из свежего
прочтения бэклога. Владелец поймал это вопросом «взял по инерции или вычитал?». Пере-проверка
бэклога (42 движковые строки со статусом «скоро») дала ДВА хвоста, которые по цене ошибки идут не
позже денежного стопа, и оба дёшевы. Они входят в пак райдерами, а не отдельным паком, потому что
каждый — одно касание, а собирать под них третью сессию дороже, чем сделать здесь.
**РАЙДЕР Р2 (строка 251, артефакт контура) СНЯТ С ПАКА 05.09 — движковая половина УЖЕ СДЕЛАНА.**
`backend/internal/config/pipeline.go`, греп `CheckMiningContrast`: при включённом гейте терминологии и заданном
`contrast_path` недоступный файл даёт ОТКАЗ ЗАГРУЗКИ, и текст отказа называет путь, говорит «deployment-provided and NOT
in git» и последствие. Непокрыто только «откуда взять артефакт» — это ОПЕРАТОРСКИЙ текст рантбука, и он заказан
платформенному паку. ⚠ Прежняя редакция велела тебе «проверить первым делом, сделано ли уже» — это была моя работа до
выдачи, а не твоя после.
**Строки 198 и 254 — БЕСХОЗНЫ, и это надо знать обеим сторонам:** 198 (апгрейд движка стирает замечания читателя) и
**254 (пустой файл ⇒ интейк УНИЧТОЖАЕТ загрузку — потеря пользовательских данных на первом же шаге)** требуют согласования
движка и платформы, и потому не взяты ни здесь, ни в платформенном паке. Пропуск подписан сознательно; считаешь иначе — пинг ДО работы.
**Что ещё в райдеры НЕ вошло и почему:** строка 283 (структура глав для выдачи) — гейт беты, но это
СВОЙ пак и своё окно пере-снапшота; строки 253/273 — швы, требующие согласования с платформой;
256267 — то, что зона чинит прямо сейчас в незакрытой приёмке прошлого пака.
## 4-тер. Пять рисков реализации — названы зоной, проверить ОБЯЗАН
(а) защёлка на уровне волны, не у воркера · (б) учёт объёма (`volume.go`, `bound()`/`reconcile`): частичная
волна под потолком — НОВАЯ форма для этих счётчиков, и они уже дважды ловили ложные числа · (в) событие
`ceiling` и exit 4/`paused` обязаны сработать так же и не задержаться · (г) дневной потолок делит ветку с
книжным — проверить явно · (д) эскалационный хоп: убедиться, что его деградация не опирается на саму отмену.
**Каждый из пяти предъявляется ЯВНО:** в отчёте — команда и её вывод либо посадка и её цвет. «Проверил» без артефакта не считается: это ровно та вырожденная форма, которую канон велит ловить в промтах.
## 5. Мандат самопроверки ИСПОЛНЕНИЕМ
Батарея + **собственные адверсариальные посадки ВНЕ списка автора** через `cmd/tmmutate` (каталог 152
записи — пополняешь). **Субагенты РАЗРЕШЕНЫ явно**, модель называй имени. Обязательное условие приёмки:
посадка **«под потолком волна погасила допущенный вызов» предъявлена КРАСНОЙ**.
**SURVIVED не является находкой, пока не показано, что посадка ВООБЩЕ меняет поведение** — норма
куплена эквивалентной посадкой оркестратора (обход окна с обратной стороны воспроизводил оригинал).
⚠ Мутации — только на ЗАКОММИЧЕННОМ дереве; на копии — `GOFLAGS=-buildvcs=false`.
⚠ Каталог гонять ЦЕЛИКОМ: протухшая запись даёт `ROTTED` и не кладёт прогон.
## 6. Предметные оси ревью — ТРИ, и у каждой свой артефакт
⚠ Оси, а не список проверок: у каждой названо, ЧЕМ ты предъявишь результат. Сессия вправе заменить ось с аргументом.
**ВСЕ ТРИ ПРЕДЪЯВЛЯЮТСЯ ЗА $0** — на фейк-клиенте батареи и голдене. **Платный прогон в этот пак НЕ входит**: он идёт
только по санкции владельца с названным потолком, и промт её не даёт.
· **Деньги под параллельностью.** Артефакт: прогон с `waves.workers > 1` и потолком, которого хватает
на часть волны — леджер до и после, показывающий, что допущенное доработано, а новое не начато.
· **Детерминизм резюме после частичной волны.** Артефакт: прогон, остановленный деньгами, и его
резюм — совпадение чекпойнтов и отсутствие пере-оплаты доработанного.
· **Шов наружу.** Артефакт: событие `ceiling` с недостающей суммой, прочитанное СО СТОРОНЫ ПОТРЕБИТЕЛЯ
(не из своего кода), и версия потока, сдвинутая по правилу шва.
## 6-бис. ОБЯЗАТЕЛЬНОЕ ДЛЯ КОДОВОГО ПРОМТА — пять строк канона
· **Перед отчётом сверь КАЖДЫЙ клейм с результатом инструмента ЭТОЙ сессии.** Не с памятью и не с тем,
что было верно вчера.
· **Последний абзац отчёта — план или обещание? Сделай это СЕЙЧАС**, а не пиши как намерение.
· **Править или удалять тест/голден/гейт ради зелени — НЕДОПУСТИМО.** Несогласие с тестом — пинг, не
правка. ⚠ Запрет про МОТИВ (`D39.183`): правка, вызванная сменой поведения, которая ЗАКАЗАНА этим
промтом, — обслуживание, и держать протухший тест не нужно; такая правка ОБЪЯВЛЯЕТСЯ в отчёте — что
изменилось в поведении, какой тест это описывал, куда уехала гарантия.
· **Дифф `^func Test` — ИСПОЛНЕНИЕМ, не по памяти:** приложи вывод, а не утверждение «тестов стало больше».
· **Интервальная самоверификация субагентом** в длинной сессии, против ЯВНЫХ критериев, а не «посмотри,
всё ли хорошо».
## 7. Записка-план ДО работы
Комплектность против заказа — механически, таблицей: пункт → файл → тест → посадка. До первой правки.
## 8. Заявление = команда
Каждое число и каждая категорика отчёта — с командой получения. Приёмка пере-ранит. ⚠ Отрицательное
утверждение («такого пути нет») выводится ТОЛЬКО из названного грепа, и команда приводится в тексте:
за сутки трижды ловили отрицания, выведенные из команд, которые не сработали.
## 9. Эхо-протокол старта
≤10 строк «скоуп / инварианты / не-делать» ДО работы — в прямой канал, первым действием.
## 10. Obstacle reporting
Обязательная секция отчёта: что НЕ удалось, что не проверено, что осталось гипотезой. ⚠ **Отчитаться о
баге не значит его сдать** — норма куплена вчера: найденное и не починенное не превращается в долг
решением о темпе.
## 11. Канал вопросов
Конфликт промта с кодом или доками — **пинг, не интерпретация**. Право сказать «этого делать не надо» с
аргументом — есть, и им пользуются: за сутки зона трижды опровергла оркестратора по существу.
## 12. Прямой канал
Механизм — `CLAUDE.md` §«Связь между сессиями». Впиши свой блок первым делом; адрес оркестратора бери
оттуда же и сверяй `ListAgents` перед отправкой. Канала нет ⇒ **НЕ искать**, вопрос секцией в отчёт.