Reconcile the two prompts on manifest deploy order and hand the platform the runbook line whose advice its own intake gate makes destructive

This commit is contained in:
heaven 2026-09-02 23:31:08 +03:00
parent 09a7d12130
commit 25b4db6ca8
2 changed files with 74 additions and 66 deletions

View file

@ -1,11 +1,10 @@
# Промт сессии: БЭКЕНД — «число согласия на пути второй покупки» # Промт сессии: БЭКЕНД — «число согласия на пути второй покупки»
> **Роль:** бэкенд. **Зона записи:** `backend/`. **Не коммитишь** — дерево готовишь и передаёшь на > **Роль:** бэкенд. **Зона записи:** `backend/`. Чужие зоны (`platform/`, `frontend/`, `eval/`)
> лендинг оркестратору. Чужие зоны (`platform/`, `frontend/`, `eval/`) читаешь, не правишь; в `docs/` > читаешь, не правишь; в `docs/` пишешь ТОЛЬКО в секцию «Бэкенд» журнала `docs/PROGRESS.md` — это
> пишешь ТОЛЬКО в секцию «Бэкенд» журнала `docs/PROGRESS.md` — это единственное разрешённое каноном > единственное разрешённое каноном исключение. **Не коммитишь** и не трогаешь индекс и историю —
> исключение. Git: никаких `git add -A`/`git add .`/`git commit -a`, никаких `reset --hard`, `rebase`, > полный список запретов и причина: `CLAUDE.md`, «Git-координация мультисессий».
> `checkout` поверх грязного дерева — рядом идут параллельные сессии, и rewrite стирает их работу > Норматив стиля — `docs/architecture/12-go-style-notes.md`.
> безвозвратно. Норматив стиля — `docs/architecture/12-go-style-notes.md`.
## Какая проблема и что изменит твой результат ## Какая проблема и что изменит твой результат
@ -61,9 +60,9 @@
Замер вреда из приёмки: **`$0.003640` против честных `$0.036400`** при `HistoricalRows=0` Замер вреда из приёмки: **`$0.003640` против честных `$0.036400`** при `HistoricalRows=0`
(`grep -on '\$0.003640 против честных \$0.036400' docs/archive/PROGRESS-2026-08-17.md``68:...`). (`grep -on '\$0.003640 против честных \$0.036400' docs/archive/PROGRESS-2026-08-17.md``68:...`).
**Проверь исходное состояние САМ и не бери с моих слов.** Оркестратор однажды утверждал, что «шапка **Проверь исходное состояние САМ и не бери с моих слов.** Противоречащая ратификации шапка — в
`rebill.go` заявляет обратное ратифицированному», и **это не подтвердилось** там речь про `$0`-строку. `reprice.go` (см. выше); шапка `rebill.go` про это НЕ говорит, там речь про `$0`-строку. Формулируй
Противоречащая шапка есть, но в `reprice.go` (см. выше). Формулируй по коду, который увидишь. по коду, который увидишь.
**«Решаешь сам и аргументируешь»:** форма хранения и проводки «модели, которую стадия резолвит сейчас» **«Решаешь сам и аргументируешь»:** форма хранения и проводки «модели, которую стадия резолвит сейчас»
в числе согласия; конкретная формула округления вверх при незнании; точные слова оговорки и обеих в числе согласия; конкретная формула округления вверх при незнании; точные слова оговорки и обеих
@ -224,8 +223,10 @@ go run ./cmd/tmmutate -root . -logs /tmp/mutlogs # сохранить пол
`88`, `"tm-manifest-v2"`). Окна из двух версий НЕТ. Поэтому «платформа первой» так же смертельно, как `88`, `"tm-manifest-v2"`). Окна из двух версий НЕТ. Поэтому «платформа первой» так же смертельно, как
«движок первым»: выкатив любую сторону в одиночку, ты отправляешь КАЖДУЮ новую книгу в отказ «движок первым»: выкатив любую сторону в одиночку, ты отправляешь КАЖДУЮ новую книгу в отказ
(`ReasonParserUnavailable`, который жжёт бюджет попыток). Бамп формы = **стоп-мир** либо специально (`ReasonParserUnavailable`, который жжёт бюджет попыток). Бамп формы = **стоп-мир** либо специально
построенное временное окно двух версий. ⚠ Это исправление: прежняя редакция промта писала «форма построенное временное окно двух версий. ⛔ **Рантбук зоны платформы советует обратное:**
манифеста требует платформа первой» — носителя у этой фразы в корпусе НЕТ. `platform/deploy/README.md:213`=`сначала платформа, потом движок`. По коду этот совет опасен —
дефект чужой зоны, он передан платформенному паку; тебе он важен тем, что «платформа первой» НЕ
является безопасным обходом, если ты вдруг упрёшься в форму манифеста.
- **Схема хранилища — «движок первым»**, и это документировано: движок первым → `tmctl migrate` по - **Схема хранилища — «движок первым»**, и это документировано: движок первым → `tmctl migrate` по
каждой книге до прогонов → и только потом платформа (D39.158 п.6, каждой книге до прогонов → и только потом платформа (D39.158 п.6,
`grep -n 'движок первым' docs/architecture/05-decisions-log.md``715`). `grep -n 'движок первым' docs/architecture/05-decisions-log.md``715`).
@ -286,10 +287,10 @@ EXIT=0, `golangci-lint` `0 issues`). Зелёная батарея НИЧЕГО
предпосылки, каждая из которых ломается (`sed -n '86,112p' backend/internal/pipeline/reprice.go`). Твоя предпосылки, каждая из которых ломается (`sed -n '86,112p' backend/internal/pipeline/reprice.go`). Твоя
правка ложится прямо на него. правка ложится прямо на него.
**Править или удалять тест ради зелени — НЕДОПУСТИМО.** Правка, вызванная сменой поведения, которая Запрет подгонки тестов — `CLAUDE.md` (D39.183). Край, который тебе понадобится: **этот промт
**заказана этим промтом или ратифицирована**, — обслуживание, и держать протухший тест не нужно; но она заказывает смену поведения в пунктах 1 и 3** (обещание точности снимается, текст отказа меняется), и
**ОБЪЯВЛЯЕТСЯ в отчёте**: что изменилось в поведении, какой тест это описывал, куда уехала гарантия. протухший под неё тест правится как обслуживание — но правка ОБЪЯВЛЯЕТСЯ в отчёте: что изменилось,
Заказанность решает ЗАКАЗ, а не ты: нет в этом промте и нет ратификации — **пинг** (D39.183). какой тест это описывал, куда уехала гарантия. Нет в промте и нет ратификации — **пинг**.
⚠ Перед отчётом **сверь каждый клейм с результатом инструмента ЭТОЙ сессии**. Последний абзац — план ⚠ Перед отчётом **сверь каждый клейм с результатом инструмента ЭТОЙ сессии**. Последний абзац — план
или обещание? Сделай сейчас. или обещание? Сделай сейчас.
@ -319,11 +320,7 @@ EXIT=0, `golangci-lint` `0 issues`). Зелёная батарея НИЧЕГО
## Прямой канал ## Прямой канал
Механизм — `CLAUDE.md`, секция «Связь между сессиями». **Указатель: файл `/tmp/textmachine-channel`** Механизм целиком — `CLAUDE.md`, «Связь между сессиями»: свой блок в `/tmp/textmachine-channel`, сверка
впиши туда СВОЙ блок (`role=` `session=` `ref=` `written=` `note=`; имя — из `ListAgents`) первым делом, с `ListAgents` перед отправкой, канала нет — нормальный случай, сессии подряд не опрашивать. Что
дописывая в конец и не трогая чужие блоки. Эхо-записку (блок выше) отправь первым действием по адресу из добавляет этот пак: **эхо-записку отправь ПЕРВЫМ действием по адресу оркестратора** — это и есть
файла — это заодно и проверка канала. проверка канала.
⚠ Адрес из файла **не доказательство, что сессия жива**: файл переживает смерть сессии, а `ListAgents`
нет. **Сверяйся с `ListAgents` перед тем, как писать.**
⚠ Нужной роли в файле нет, файла нет или имя не отвечает ⇒ **КАНАЛА НЕТ, и это НОРМАЛЬНЫЙ случай: НЕ
ищи, НЕ опрашивай сессии подряд.** Вопрос — секцией в отчёт; владелец прочитает и пере-передаст.

View file

@ -1,10 +1,9 @@
# Промт сессии: ПЛАТФОРМА, пак P13 — «шов возврата оплаченного прогона» # Промт сессии: ПЛАТФОРМА, пак P13 — «шов возврата оплаченного прогона»
> **Роль:** платформа. **Зона записи:** `platform/`. **Не коммитишь** — дерево готовишь и передаёшь > **Роль:** платформа. **Зона записи:** `platform/`. Чужие зоны читаешь, не правишь. **Не коммитишь**
> на лендинг оркестратору (канон — `CLAUDE.md`, таблица ролей). Чужие зоны читаешь, не правишь. > и вообще не трогаешь индекс и историю — почему именно, и полный список запретов: `CLAUDE.md`,
> ⛔ Ни `git commit`, ни `add`, ни `reset`/`checkout`/`stash`/`clean` — ничего, что двигает индекс или > «Git-координация мультисессий».
> историю: рядом работают параллельные сессии, и их незакоммиченные файлы твой индекс унесёт. > **Обязателен к ссылке:** `platform/docs/ENGINEERING_STANDARDS.md`; отступление — пинг, не
> **Обязателен к ссылке:** `platform/docs/ENGINEERING_STANDARDS.md`; отступление от него — пинг, не
> самовольство. Направление зоны — `platform/docs/PLATFORM_DIRECTION.md`. > самовольство. Направление зоны — `platform/docs/PLATFORM_DIRECTION.md`.
## Какая проблема и что изменит твой результат ## Какая проблема и что изменит твой результат
@ -92,7 +91,7 @@ cd platform && awk -F'|' '/^\| PD-/{l=tolower($0);
**Каждая посадка мутации в твоём отчёте обязана нести строку «гонялось при DSN = да».** Иначе пак **Каждая посадка мутации в твоём отчёте обязана нести строку «гонялось при DSN = да».** Иначе пак
проверит себя ровно тем способом, каким заводились ряды, которые он чинит. проверит себя ровно тем способом, каким заводились ряды, которые он чинит.
## Состав пака — четыре правки и один гейт ## Состав пака — четыре правки, гейт и одна строка рантбука
### 1. ГЛАВНОЕ — денежный бюджет прогона ЧИТАТЬ, а не пере-выводить из ставки ### 1. ГЛАВНОЕ — денежный бюджет прогона ЧИТАТЬ, а не пере-выводить из ставки
@ -282,6 +281,20 @@ cd platform && for M in any distinct; do printf "%s: " "$M"; awk -F'|' -v mode="
и не «чинить» подгонкой — это тот же запрет, что подгонка тестов; непонятно или кажется неправым → и не «чинить» подгонкой — это тот же запрет, что подгонка тестов; непонятно или кажется неправым →
пинг. пинг.
### 6. МЕЛКОЕ, найденное при сборке промта: рантбук ТВОЕЙ зоны советует деструктивный порядок деплоя
`platform/deploy/README.md:213`=`сначала платформа, потом движок` — «Правило то же, что у схемы
хранилища: сначала платформа, потом движок». По коду безопасного порядка у формы манифеста НЕТ:
гейт интейка — строгое равенство ОДНОЙ константе, окна двух версий нет (обе ссылки — в разделе
ПОРЯДОК ДЕПЛОЯ ниже). Платформа, выкаченная первой со знанием новой формы, отправит в
`parser_unavailable` КАЖДУЮ книгу ещё не обновлённого движка — ровно тот симптом, который абзац
рантбука строкой выше описывает как беду ОБРАТНОГО порядка.
**Делай РОВНО так:** ряд в `docs/DEFECT_REGISTER.md` (класс `doc`) + правка строки рантбука.
**Решаешь сам и аргументируешь:** формулировка — назвать бамп формы стоп-миром или описать временное
окно двух версий как условие, при котором безопасный порядок вообще появляется.
⚠ Увидишь в коде окно версий, которого я не нашёл, — это находка, а не твоя ошибка: скажи и не чини.
## Границы — что НАМЕРЕННО не берём ## Границы — что НАМЕРЕННО не берём
- **`PD-412`/`PD-413` (LATERAL в полосном агрегате).** Находки настоящие и замеренные (1.359 мс → - **`PD-412`/`PD-413` (LATERAL в полосном агрегате).** Находки настоящие и замеренные (1.359 мс →
@ -304,34 +317,40 @@ cd platform && for M in any distinct; do printf "%s: " "$M"; awk -F'|' -v mode="
## ⚠ ПОРЯДОК ДЕПЛОЯ — почему пак безопасен параллельно бэкенду ## ⚠ ПОРЯДОК ДЕПЛОЯ — почему пак безопасен параллельно бэкенду
Зоны независимы по коду (разные модули, перекрёстных импортов нет в обе стороны, `go.work` в корне Зоны независимы по коду (разные модули, перекрёстных импортов нет в обе стороны, `go.work` в корне
отсутствует), но **НЕ по деплою**, и сцеплений ДВА с противоположным порядком: форма манифеста ⇒ отсутствует), но **НЕ по деплою**, и сцеплений ДВА.
«сначала платформа, потом движок» (незнакомая форма → `parser_unavailable`); **схема хранилища
ДВИЖКА (v16)** и обход ⇒ «движок первым → `tmctl migrate` по каждой книге → и только потом платформа - **Форма манифеста БЕЗОПАСНОГО ПОРЯДКА НЕ ИМЕЕТ.** Гейт интейка — строгое равенство ОДНОЙ константе
снимает свой обход» (D39.158 п.6). (`internal/ingest/manifest.go:112`=`if m.Version != KnownManifestVersion`; сама константа — `:88`=`KnownManifestVersion = "tm-manifest-v2"`).
Окна из двух версий нет, поэтому «платформа первой» ровно так же смертельно, как «движок первым»:
односторонняя выкатка отправляет КАЖДУЮ книгу в `parser_unavailable`, который жжёт бюджет попыток.
Бамп формы = стоп-мир либо специально построенное временное окно двух версий.
- **Схема хранилища ДВИЖКА** ⇒ «движок первым → `tmctl migrate` по каждой книге → и только потом
платформа снимает свой обход» (D39.158 п.6). Голова схемы сегодня 16
(`backend/internal/store/migrate.go:485`=`func SchemaHead() int`, `len(migrations)`) — это персистентная
память ДВИЖКА, а не Postgres платформы.
**Поэтому пак НЕ меняет: форму манифеста · схему хранилища ДВИЖКА · версию контракта.** Понадобилось **Поэтому пак НЕ меняет: форму манифеста · схему хранилища ДВИЖКА · версию контракта.** Понадобилось
**стоп и пинг**, не «сделаю аккуратно». **стоп и пинг**, не «сделаю аккуратно». Платформенная миграция этим абзацем НЕ запрещена: по пункту 1
она не нужна (сумма уже персистится) и потому не заказана; понадобилась — тоже пинг, но по другому
⚠ Уточняю, потому что прежняя редакция этого места читалась двояко: «схема хранилища v16» — это основанию.
персистентная память ДВИЖКА (D39.158 п.1), а не Postgres платформы. Платформенная миграция этим
абзацем не запрещена — она не нужна по пункту 1 (сумма уже персистится) и по этой причине не
заказана. Понадобилась — тоже пинг, но по другому основанию.
## Свобода и её разметка ## Свобода и её разметка
**«Делай РОВНО так» (отступление = пинг):** **«Делай РОВНО так» (отступление = пинг):**
- предусловие хоста (четыре условия) · строка «DSN = да» у каждой посадки; - предусловие хоста (четыре условия) · строка «DSN = да» у каждой посадки;
- **ФАКТ каждой из пяти правок** — что именно закрывается: (1) `reopen` читает хранимую сумму в ОБОИХ - **ФАКТ каждой из шести правок** — что именно закрывается: (1) `reopen` читает хранимую сумму в ОБОИХ
местах, `:1363` и `:1397`, схему платформы не трогая; (2) ключ печатается на пути ошибки; местах, `:1363` и `:1397`, схему платформы не трогая; (2) ключ печатается на пути ошибки;
(3) свойство «чужая строка не карантинит нашу проекцию» с тремя оговорками пункта 3 (декод остаётся (3) свойство «чужая строка не карантинит нашу проекцию» с тремя оговорками пункта 3 (декод остаётся
выше · понижение только при известном `want` · при `want == ""` валидация полная); (4) цель `check` выше · понижение только при известном `want` · при `want == ""` валидация полная); (4) цель `check`
печатает ВСЕ условия; (5) гейт против класса живёт в зоне платформы; печатает ВСЕ условия; (5) гейт против класса живёт в зоне платформы; (6) ряд регистра и правка
строки рантбука;
- **обязательные посадки у пунктов 2 и 3**; - **обязательные посадки у пунктов 2 и 3**;
- границы выше · три запрета из порядка деплоя · запрет трогать `docs/scripts/counts.py`. - границы выше · три запрета из порядка деплоя · запрет трогать `docs/scripts/counts.py`.
**«Решаешь сам и аргументируешь» — ФОРМА и только она:** какую колонку холда читать и как быть без **«Решаешь сам и аргументируешь» — ФОРМА и только она:** какую колонку холда читать и как быть без
холда · форма печати ключа · форма ручки снятия карантина · форма печати условий в `Makefile` · холда · форма печати ключа · форма ручки снятия карантина · форма печати условий в `Makefile` ·
место, предикат и порог гейта пункта 5 · остальной состав посадок · порядок работ внутри пака. место, предикат и порог гейта пункта 5 · формулировка правки рантбука в пункте 6 · остальной состав
посадок · порядок работ внутри пака.
⚠ Катч-олла «всё остальное — сам» больше нет: если чего-то нет ни в одном списке — это пинг, а не ⚠ Катч-олла «всё остальное — сам» больше нет: если чего-то нет ни в одном списке — это пинг, а не
твоё усмотрение. твоё усмотрение.
@ -340,14 +359,15 @@ cd platform && for M in any distinct; do printf "%s: " "$M"; awk -F'|' -v mode="
Батарея зелёная — это НЕ отчёт. Обязательны все три: Батарея зелёная — это НЕ отчёт. Обязательны все три:
1. **Живая проба каждого из пяти пунктов состава.** Поимённо, с пометкой про DSN: 1. **Живая проба каждого пункта состава.** Поимённо, с пометкой про DSN:
- п.1 `reopen`**DSN нужен** (денежный путь `internal/runs`, 110 тестов тёмных без него); - п.1 `reopen`**DSN нужен** (денежный путь `internal/runs`, 110 тестов тёмных без него);
- п.2 `write()` — юнит-посадки идут **без DSN**, но сквозной `TestCommandsAgainstALiveDatabase` - п.2 `write()` — юнит-посадки идут **без DSN**, но сквозной `TestCommandsAgainstALiveDatabase`
в `cmd/tmplatformctl/main_test.go` **DSN-гейчен** (без DSN в `./cmd/...` скипается 6 тестов); в `cmd/tmplatformctl/main_test.go` **DSN-гейчен** (без DSN в `./cmd/...` скипается 6 тестов);
- п.3 `ingest/tail.go`**DSN не нужен**, пакет гоняется целиком (0 скипов); - п.3 `ingest/tail.go`**DSN не нужен**, пакет гоняется целиком (0 скипов);
- п.4 `Makefile` — DSN не нужен, но проба обязана гоняться при РАЗНЫХ окружениях, иначе она не - п.4 `Makefile` — DSN не нужен, но проба обязана гоняться при РАЗНЫХ окружениях, иначе она не
видит того самого дефекта; видит того самого дефекта;
- п.5 гейт — DSN не нужен. - п.5 гейт — DSN не нужен;
- п.6 рантбук — кода не касается, «проба» это ряд регистра и `counts.py --check` зелёным.
2. **Собственные адверсариальные посадки ВНЕ списка выше.** 2. **Собственные адверсариальные посадки ВНЕ списка выше.**
3. **Отдельный проход по СВОЕЙ ГОТОВОЙ работе** свежим контекстом. ⚠ Класс, купленный прошлой сменой: 3. **Отдельный проход по СВОЕЙ ГОТОВОЙ работе** свежим контекстом. ⚠ Класс, купленный прошлой сменой:
веер по исходным уликам находит втрое меньше, чем веер, читающий готовый результат. веер по исходным уликам находит втрое меньше, чем веер, читающий готовый результат.
@ -385,10 +405,10 @@ a second hello to the same file and numbers from 1 again») и `backend/internal
принимается ТОЛЬКО со списком того, что проверялось; голое «находок нет» означает, что веер не принимается ТОЛЬКО со списком того, что проверялось; голое «находок нет» означает, что веер не
отработал — задание переформулируй и гоняй заново. отработал — задание переформулируй и гоняй заново.
**Править или удалять тест/гейт ради зелени — НЕДОПУСТИМО.** Запрет про МОТИВ (D39.183): правка, Запрет подгонки тестов и гейтов — `CLAUDE.md` (D39.183). Здесь важен один его край: заказанность
вызванная сменой поведения, которая ЗАКАЗАНА этим промтом, — обслуживание, и **держать протухший тест решает ЗАКАЗ, а не ты, и **этот промт заказывает смену поведения в пунктах 14** — протухший под неё
не надо**; но она ОБЪЯВЛЯЕТСЯ в отчёте (что изменилось в поведении, какой тест это описывал, куда тест правится как обслуживание, но правка ОБЪЯВЛЯЕТСЯ в отчёте (что изменилось, какой тест это
уехала гарантия). Несогласие с тестом — **пинг**, не правка. описывал, куда уехала гарантия).
## Отчёт ## Отчёт
@ -397,12 +417,11 @@ a second hello to the same file and numbers from 1 again») и `backend/internal
Итог — туда же. ⛔ В `docs/PROGRESS.md` платформа НЕ пишет (канон, таблица ролей). Итог — туда же. ⛔ В `docs/PROGRESS.md` платформа НЕ пишет (канон, таблица ролей).
**Каждое число и каждая категорика — с КОМАНДОЙ ПОЛУЧЕНИЯ, которая это число реально печатает.** **Каждое число и каждая категорика — с КОМАНДОЙ ПОЛУЧЕНИЯ, которая это число реально печатает.**
Приёмка пере-ранит. ⚠ Команда, печатающая «ok» вместо числа, командой получения не является — это Приёмка пере-ранит. ⚠ Команда, печатающая «ok» вместо числа, командой
ровно та ошибка, на которой споткнулась прежняя редакция этого промта. получения не является.
Обязательная секция **«Что НЕ удалось и что НЕ проверено»**: исходов ТРИ, и «не проверено» ≠ Обязательная секция **«Что НЕ удалось и что НЕ проверено»**: исходов ТРИ, третий законен, и молчание
«опровергнуто» ≠ «сделано». Третий исход законен и ожидаем — молчание об упёршемся пункте дороже об упёршемся пункте дороже самого упора.
самого упора.
## Канал вопросов и право отказаться ## Канал вопросов и право отказаться
@ -415,16 +434,8 @@ a second hello to the same file and numbers from 1 again») и `backend/internal
## Прямой канал ## Прямой канал
Механизм — `CLAUDE.md`, секция «Связь между сессиями». **Впиши свой блок в `/tmp/textmachine-channel` Механизм целиком — `CLAUDE.md`, «Связь между сессиями»: впиши свой блок в `/tmp/textmachine-channel`,
первым делом** (`role=` `session=` `ref=` `written=` `note=`; имя — из `ListAgents`), дописывая в сверься с `ListAgents` перед отправкой, канала нет — это нормально и опрашивать сессии подряд не надо.
конец и не трогая чужие блоки. Что добавляет этот пак: **эхо-записку отправь ПЕРВЫМ действием по адресу оркестратора — это и есть
проверка канала**; и знай, что в файле прямо сейчас лежат блоки закрытых смен, один с пометкой
**Эхо-записку (скоуп · инварианты · не-делать, ≤10 строк) отправь ПЕРВЫМ действием по адресу «⚠ СМЕНА СДАНА 31.08 … по адресу не писать».
оркестратора из файла — это и есть проверка канала**; в зонный журнал она идёт тем же текстом.
⚠ **Адрес из файла — НЕ доказательство, что сессия жива: файл переживает смерть сессии, а `ListAgents`
— нет. Перед отправкой сверься с `ListAgents`.** В файле прямо сейчас лежат блоки закрытых смен, один
с пометкой «⚠ СМЕНА СДАНА 31.08 … по адресу не писать».
Нужной роли в файле нет, файла нет или имя не отвечает ⇒ **канала нет, и это НОРМАЛЬНЫЙ случай — НЕ
опрашивай сессии подряд**. Вопрос — секцией в отчёт; владелец прочитает и пере-передаст.