textmachine/docs/BACKEND_HONESTY_PACK_SESSION_PROMPT.md

190 lines
22 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.

# Промт: бэкенд, пак «честные числа и статусы» — строки 176 · 181 · 172-г · 187
> Выдан оркестратором №18, 16.08.2026. Запуск — по слову владельца.
> Вес пака — лёгкий-средний: четыре точечных места, приёмка инлайн.
## 0. Зачем (проблема, понятная без истории проекта)
Движок — CLI (`tmctl`), который переводит книгу платными вызовами LLM и которым снаружи управляет
процесс-супервизор (платформа). Наружу он сообщает три вещи: **число денег**, **код выхода** и
**вердикт гейта**. Сегодня в четырёх местах сообщаемое расходится с происходящим:
1. **Число, на которое оператор даёт согласие при пере-покупке, посчитано по СТАРЫМ ценам.** Цены
провайдера сменились 16.08 (до ×4.4 в пике), проекция пере-покупки складывает исторический
`cost_usd`, а резерв и расчёт считают новой таблицей. Оператор соглашается на одну сумму, платит
другую. Траты защищены потолками — врёт именно ЧИСЛО СОГЛАСИЯ (строка 181).
2. **Паника Go-рантайма неотличима от успеха.** Непойманная паника даёт exit 2, а 2 в контракте
означает «завершено, есть флагнутые главы» — потребитель записывает упавшему посреди работы
прогону «готово». Деньги при этом целы (считаются из `status --json`), врёт статус (строка 176).
3. **Ратифицированный порог приёмки классификатора не доехал до тестового рига.** Владелец 15.08
подписал ВЫБОРОЧНУЮ форму порога, риг требует прежнюю — и сам предупреждает, что порог и выборка
расходятся. Ближайший прогон вахты упадёт ложно (строка 172-г).
4. **Два комментария кода описывают снятое поведение** — читатель кода получает неверный закон о том,
что попадает в `memory_version` (строка 187).
**Что решит твой результат:** ни одно из четырёх мест больше не врёт, и каждое прибито тестом,
который на до-фиксном коде ПАДАЕТ. После пака можно честно пере-прогонять старую книгу (сейчас
нельзя — п.1) и честно читать исход прогона снаружи (п.2).
## 1. Зона записи и git
Пишешь ТОЛЬКО в `backend/`. Итог сессии — краткой записью в `docs/PROGRESS.md`, секция «Бэкенд»
(это единственный файл вне `backend/`, куда тебе можно писать).
**Ты не коммитишь — лендит оркестратор.** `git add` / `git commit` / `git reset` / `git checkout` /
`git stash` не звать вовсе; файлы застейдженными не оставлять.
Карв-аут к «пишешь только в `backend/`»: **пробные проекты в `~/books/…` — легитимная запись** (они вне
git, и норма «персист, не scratch» требует, чтобы сырьё платной пробы легло рядом с проектом пробы, а
не в `/tmp`). Это касается только пункта 5.
**В дереве прямо сейчас работают ДВЕ чужие живые сессии** — полигон (`eval/`, `docs/experiments/`)
и платформа (`platform/`). Их незакоммиченные файлы читать можно, трогать — нельзя ни при каких
обстоятельствах. `.env` не читать никогда (там ключи). `frontend/` не трогать.
## 2. Карта чтения (≤5, больше не нужно)
1. `CLAUDE.md` — гардрейлы и инвариант общности (Go не ветвится по языковой паре).
2. `backend/README.md` + `docs/architecture/12-go-style-notes.md` §0 — норматив зоны.
3. Тела строк **176 · 181 · 172-г · 187** в таблице «Бэклог» файла `docs/PROGRESS.md` — это ЗАКАЗ;
в них лежат `file:line` отправные точки. Строки писала нейросеть: якоря могли уплыть, формулировка
могла устареть — **код первичен**, расхождение строки с кодом называй вслух в отчёте.
4. `docs/architecture/05-decisions-log.md`: **D39.131** (половина 05 контракта кодов выхода) ·
**D39.134 п.2** (полоса отказов 1019 и её обещание) · **D39.137** (пере-пин цен — откуда взялась
строка 181). Греп по номеру: сначала живой файл, потом слайсы `docs/archive/architecture/`.
5. `docs/experiments/00-provider-quirks.md`**только если** дойдёт до пункта 5 (живой прогон вахты).
Всё остальное — код, и его ты достаёшь сам.
## 3. Состав
Пункты 14 — **«делай РОВНО так» по ПРЕДМЕТУ** (что чинится, решено); **форма фикса внутри — твоя,
аргументируй в отчёте**. Отступление от предмета = пинг, не интерпретация.
**1. Строка 181 — число согласия на пере-покупку.** Проекция пере-покупки обязана считать ТОЙ ЖЕ
ценовой таблицей, которой считают резерв и расчёт, а не складывать исторические суммы. Отправные
точки заказа: `internal/pipeline/rebill.go` (сложение исторического `cost_usd`; гейт согласия и его
порог), `internal/pipeline/stagerun.go` (резерв и сеттл новой таблицей). **Тест обязателен и обязан
падать на до-фиксном коде** (сценарий: единицы куплены по старой цене → цена сменилась → согласие
спрашивают на новую сумму). ⚠ Комментарий `rebill.go` про «over-estimating is the safe direction»
после фикса обязан стать правдой или уйти.
**`projected_book_usd` у `status`В СКОУПЕ, а не «проверь и назови»**: заказ строки утверждает ту же
болезнь, и оставить её значит оставить `status` врущим. ⚠ **Развилка, которую обязан разрешить явно:**
сам ПОРОГ согласия тоже считается из этой проекции — починить числитель новой таблицей и оставить базу
порога исторической значит получить полу-исторический гейт. Реши обе половины вместе и назови решение
в отчёте; считаешь, что вторая половина не влезает — **пинг**, а не тихое сужение.
**2. Строка 176 — паника не должна читаться как успех.** Непойманная паника рантайма обязана
приходить наружу кодом, который потребитель прочтёт как ПРОВАЛ.
**Обе полосы кодов — ЗАМОРОЖЕНЫ, это шов, их словарь двигается только ратификацией.**
- **05 не трогать** (ратифицированный словарь, D39.131; шапка `cmd/tmctl/main.go`). В частности
**exit 2 НЕ переносить**: значение «завершено с флагами» зашито у потребителя намертво
(`platform/internal/ingest/exit.go:24,89` · `platform/internal/runs/reconcile.go:484``ready`), и
«развести номера, оставив полосу 1019 нетронутой» **сломает шов, не нарушив буквы этого запрета**
каждый честно флагнутый прогон станет `failed`, а чтение денег сломается вместе с ним.
- **1019 не расширять и для паники НЕ использовать** — полоса обещает «ничего не произошло, ничего
не потрачено, ничего не записано» (D39.134 п.2г), а паника случается посреди оплаченной работы;
посадить её на 19 значит соврать наоборот.
- **Безопасное направление:** код, который сегодняшняя платформа читает как `failed` — то есть **1**
либо номер ВНЕ обеих полос. Выбрал не 1 — аргумент в отчёт и пинг, потому что это словарь шва.
**Ловушка, на которой фикс выглядит зелёным и молчит на настоящем пути:** платный путь исполняется
пулом воркер-горутин (`internal/pipeline/waverun.go:260`), а `recover` в `main`/`run` ловит только
главную горутину. **Предмет — «паника ЛЮБОЙ горутины движка не читается как успех»**, и тест обязан
это покрывать; фикс, падающий только на синтетической панике в main, заказ не закрывает.
Стек паники обязан доехать до stderr: диагностика важнее лаконичности.
**Попутно тем же касанием** (сам заказ строки): usage-строка `cmd/tmctl/invocation.go:96` не знает
команд `migrate` / `backup` / `seed-lint`. ⚠ Её байты запинены тестом замороженного контракта
(`cmd/tmctl/invocation_test.go:23`) — **обновить тест ВМЕСТЕ со строкой здесь санкционировано**
(ратифицированная правка контракта, D39.134 п.3): это не подгонка под зелень, и §4-запрет сюда не
применяется. Любая ДРУГАЯ правка замороженных байтов — пинг.
**3. Строка 172-г — выборочный порог в риг вахты.** Внести ратифицированную форму порога
(**D39.136 п.6б: «≥4/5 прогонов при N=5 достигают 6/6»**) в `internal/pipeline/live_reprobe_test.go`
вместо действующего «6/6 на КАЖДОМ прогоне». Комментарий рига, объявляющий расхождение порога и
выборки открытым вопросом владельца, обязан быть переписан: вопрос ЗАКРЫТ, сошлись на выборочной
форме. Риг под тегом `live` — компилируемость проверяется `make battery``vet` оба набора тегов).
**Порог не «смягчить», а внести ратифицированный.** Подгонять гейт под желаемый результат
недопустимо; если считаешь ратифицированную форму неверной — пиши пинг, не правку.
⚠ Ратифицирована форма **для N=5**; риг допускает переопределение размера выборки переменной
окружения — зафиксируй в коде и комментарии, что порог определён на N=5, а иное N выводит прогон
из-под гейта (изобретать формулу для произвольного N — не твоя работа, это ратификация).
**4. Строка 187 — два лживых комментария.** `internal/pipeline/snapshot.go` («auto/draft исключены
per D8») и докстринг `internal/membank/memory.go` («Approved-only») описывают до-паковое поведение;
код с пака-20 сворачивает в хеш КАЖДУЮ строку любого статуса. $0, поведение не двигается.
**5. Живой прогон вахты весов — ТОЛЬКО при явной санкции владельца в твоём запуске.** Если
санкция названа: прогнать риг из п.3 живьём (`TM_LIVE=1 TM_CLASSIFY6_CONFIG=<стендовый book.yaml>
go test -tags live -run TestLiveClassifierHarmSet -v ./internal/pipeline/`), сырьё персистить рядом с
проектом пробы, ЛЕДЖЕР не сбрасывать, принимать только `finish=stop`, потратить не больше названной
владельцем суммы. ⚠ **Стартовать вне пиковых окон DeepSeek (0104 и 0610 UTC)** — в пике вызов
стоит вдвое; суммы копеечные, но правило стоячее. **Санкции нет в твоём запуске — пункт НЕ исполняется**, и это не obstacle, а
норма: платные вызовы без явно названной суммы запрещены.
**Чего НЕ делать (жёстко).**
- Не трогать ничего, что двигает провод: тела промптов, состав инъекции, версии снапшота,
`RequestHash`, `memory_version`, голден. Этот пак **wire-нейтрален** — все правки обязаны оставить
голден бит-в-бит; расхождение голдена = стоп и пинг, а не пере-съём голдена.
- Не чинить попутно другие строки бэклога, даже если увидишь. Увидел — **в отчёт списком находок**,
оркестратор заведёт строки.
- Не ветвить Go-логику по языковой паре (инвариант общности): ревью-вопрос «заработает ли на паре,
которой в репо нет, без правки Go».
- Не запускать платных вызовов вне пункта 5.
## 4. Самопроверка ИСПОЛНЕНИЕМ (обязательный механизм, не перечитывание)
- **Батарея:** `cd backend && make battery` — EXIT=0, и в её хвосте список SKIP: каждый скип объясни
(скип, который ты не объяснил, читается как непокрытое место).
- **Голден бит-в-бит** — командой (`go test ./internal/pipeline/ -run Golden -count=1`), а не
«батарея прошла»; результат в отчёт.
- **Фиксы пунктов 1 и 2 (включая usage-строку) прибиты тестом, падающим на до-фиксном коде** — покажи
это ИСПОЛНЕНИЕМ: временно откати свой фикс (в рабочем дереве, без git-команд), покажи красный,
верни. Формулировка «тест добавлен» без красного до-фиксного прогона не принимается.
**Для пунктов 3 и 4 требование НЕ применяется и имитировать его не надо:** п.4 — правка двух
комментариев, поведения не двигает вовсе; п.3 живёт под тегом `live`, и «красный до-фиксный прогон»
там означал бы платный вызов, запрещённый вне п.5. Их доказательство другое: п.3 — компиляция ОБОИХ
тег-сетов (`make battery` гоняет `vet` по обоим) плюс юнит на пороговую арифметику, если она
выносима из платного пути; п.4 — цитата кода против цитаты комментария в отчёте.
- **Дифф `^func Test` — исполнением**: `grep -rh '^func Test' backend --include='*_test.go' | wc -l`
до и после; удалённых имён тестов быть не должно (проверь по именам, не по числу).
- **Править или удалять существующий тест/голден/гейт ради зелени — НЕДОПУСТИМО.** Несогласие с
тестом — пинг, а не правка.
- **Адверсариальное ревью финалом — механизмом: субагенты РАЗРЕШЕНЫ и ожидаются, спавнь.** ≥2
независимых ревьюера по финальному диффу, author≠reviewer: (а) **денежная линза** — по строке 181
пере-считать вручную, из сырого леджера, число согласия ДВУМЯ независимыми путями и сверить с тем,
что печатает движок. ⚠ **Только на КОПИИ стендовой БД, вне живого проекта**`translate` пишет в
проект ещё до гейта согласия (пре-флайт бэкап), и «проба на живом» испортит и стенд, и улику;
(б) **линза шва** — инвентарь ВСЕХ кодов выхода и их потребителей ЧТЕНИЕМ кода платформы
(`platform/internal/ingest/`, `platform/internal/runs/`), а не по твоему списку: изменил ли пункт 2
то, что платформа читает. Плюс **свои посадки-мутации** в новые тесты (не из ожидаемого тобой
списка). **Артефакт — таблица «находка → диспозиция»** в отчёте; ноль находок = не верить прогону,
спавнить третьего.
Считаешь, что для этого пака вернее другие оси ревью, — **замени с аргументом**; молча сузить нельзя.
- **Записка-план:** перед сдачей — таблица «пункт заказа 15 → исполнено (где) / отказ (почему)»,
механической сверкой против §3, а не по памяти.
- Сессия длинная — **интервальная самоверификация субагентом** против §3 и §4 в середине работы, не
только в конце.
## 5. Дисциплина отчёта
- **Заявление = команда.** Каждое число и каждая категорика отчёта — с командой, которой получены;
приёмка их пере-ранит. Эрудиция не улика: либо `file:line`/замер, либо пометка «мнение».
- **Перед отправкой отчёта сверь КАЖДЫЙ клейм с результатом инструмента ЭТОЙ сессии** — не с памятью
о том, как обычно бывает.
- **Последний абзац отчёта — план или обещание? Значит, сделай это сейчас**, а не пиши про это.
- **Obstacle reporting — обязательная секция:** что НЕ удалось · что не проверено · где остановился и
почему. Пустая секция при непустой работе не бывает.
- Плотность, а не объём. Без саги, без пересказа диалога, без шаблонных оговорок.
## 6. Канал вопросов и право отказа
Промт против кода, доков или спеки — **пинг через владельца, НЕ интерпретация**: промт писала
нейросеть, и он может быть неправ. Право сказать «этого делать не надо» — есть, с аргументом; такое
возражение ценнее тихой девиации. Промежуточный вопрос, блокирующий работу, — тоже пинг: не гадай.
## 7. Старт и сдача
**Эхо-протокол:** первым деливераблом — ≤10 строк «скоуп / инварианты / чего не делаю», ДО работы.
**Сдача:** запись в `docs/PROGRESS.md` секция «Бэкенд» (записка-план · команды · таблица
адверсариального ревью · obstacle · список находок вне заказа), дерево НЕзакоммиченное.