textmachine/docs/PLATFORM_P10_SESSION_PROMPT.md

240 lines
24 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.

# Промт: платформа, пак P10 — мина под правкой банка и дверь пере-прохода
> **Выдан оркестратором №19, 28.08.2026.** Основание — **D39.165** (три продуктовых развилки сняты
> словом владельца). Пак закрывает ОДНУ поломку и ОДНУ дыру, и обе лечатся теми же двумя флагами в
> одной функции сборки аргументов — поэтому это один пак, а не два.
## §0. Какая проблема и что решит твой результат
**1. Мина, которую взвёл наш собственный вчерашний лендинг.** Правка банка двигает снапшот. Движок
при сдвинутом снапшоте **останавливается ГРОМКО**, если ему не передали `--resnapshot`:
> `backend/internal/pipeline/stagerun.go:54-58` — «was started under snapshot … the config/prompts
> changed; already-paid checkpoints become invalid and calls will be re-paid; re-run with
> `--resnapshot` to accept this explicitly».
Платформа не передаёт ни его, ни `--accept-rebill` (`platform/internal/runner/engine.go:90-98`,
`TranslateArgs`). До 28.08 это не кусало: до движка не доезжало ни ключей, ни правок. Вчера
заленджены и `--keys-file`, и дверь правок банка (D39.162). Носитель — строка **199**(б).
⚠ **ТОЧНЫЙ ТРИГГЕР, без которого ты соберёшь ЛОЖНОЕ репро (эррата 28.08-и — моя ошибка, найдена
опровергателем).** Первая редакция этого промта и ноты утверждала «первый же продолжающий прогон
после первой же правки УПАДЁТ». Это ПЕРЕОЦЕНКА. Гард стреляет по СУЩЕСТВУЮЩЕМУ джобу
(`stagerun.go:47``EnsureJob` заводит джоб стадии в момент её первого исполнения), а правка в
главном окне — стоп подписи `awaiting_bank` — двигает edit-снапшот, когда edit-джобов ЕЩЁ НЕТ:
возобновление создаёт их свежими и гард молчит. **Мина бьёт по правке, сделанной ПОСЛЕ появления
edit-джобов** — пауза потолком посреди редактуры и ДОЧИТАННАЯ книга. Срочность от этого не падает:
флагманский случай продукта — «поправил имя героя в дочитанной книге» — ровно тот, где edit-джобы
существуют.
**2. Дыра: продать пере-проход нечем, а движок его умеет.** Механизм построен практически целиком:
`translate --resnapshot` после `bank-apply` определяет затронутые термином юниты **байт-сверкой**
отрендеренного запроса (`stagerun.go:88-100` — «POINTWISE RE-EDIT … the request is the same request
and the stored result is served for $0, with the row RE-PINNED»), незатронутые пере-привязывает за
**$0**, считает смету ДО первого резерва и **под порогом согласия продолжает сам, без флагов**
(`backend/internal/pipeline/rebill.go`, порог — свой у книги, иначе `min($0.50, 5% × книги)`).
Не хватает ровно платформенной половины. И канон при этом **противоречит сам себе на дочитанной
книге, в двух фразах**: правка «takes effect on the NEXT run»
(`docs/architecture/14-api-contract/openapi.yaml:505`), а поднять потолок можно только у
ПРИОСТАНОВЛЕННОЙ книги и «finished work is not bought twice» (`:590`). У дочитанной книги следующего
прогона купить нечем — **правка принята и умирает**.
**Что решит результат:** главный пользовательский цикл продукта — «поправил термин → правка доехала
в уже переведённый текст» — становится исполнимым, а купленный вчера механизм перестаёт быть
недостижимым.
## §1. Зона записи и git
**Твоя зона — `platform/`.** Итоги, находки, вопросы — зонный журнал `platform/docs/platform-PROGRESS.md`.
- **Ты НЕ коммитишь.** Лендит оркестратор после адверсариальной приёмки.
-**`backend/` НЕ ТРОГАТЬ.** Движковая половина построена и в этом паке правок не требует. Нужна
правка там — это ПИНГ, а не правка.
-**`docs/` — не твоя зона**, включая канон контракта. Контрактную половину (§3.4) ты **описываешь
предложением в своём журнале**, правлю её я. Причина не бюрократическая: канон и константа версии
обязаны сойтись в ОДНОМ коммите, а коммичу я.
- В дереве незакоммиченная работа полигона (20 позиций) — не касаться.
## §2. Карта чтения — ≤5 позиций, ЗАКОН
1. **`platform/internal/runner/engine.go:79-99`** (`TranslateArgs` — argv строится в одном месте) ·
**`platform/internal/runs/spawn.go:140-215`** (`spec`, `ceilingFor`, `bookCap`).
2. **`platform/internal/runs/runs.go:200-300`** — допуск прогона, шкала, `Pricing.Scale`; и
`platform/internal/pricing/pricing.go:50-90`.
3. **`platform/internal/ingest/resync.go:10-46`** — ⚠ **аллоулист `StatusReport`, читать ВНИМАТЕЛЬНО:
`rebill` исключён НАМЕРЕННО** («engine vocabulary that must not cross the seam, contract §2.12»).
Это не недосмотр, и §3.3 — про то, как это законно изменить.
4. **`docs/architecture/17-seam-inbound-law.md`** — закон шва: п.7 (мутирующий глагол сначала даёт
ПРОЕКЦИЮ), п.2 (посреди прогона внутрь только сигнал). ⚠ **Строка `:102` таблицы говорит, что
consent-флаги «гейчена 192» — ЭТОТ ГЕЙТ СНЯТ, см. §0-бис ниже. Не откажись от пака, упершись в
неё.**
5. **`docs/architecture/05-decisions-log.md`, тело D39.165** — основание всего пака (греп `^## D39.165`).
## §0-бис. Гейт, который СНЯТ — знать до чтения закона шва
`D39.144` п.1 запрещает **проектировать механику** пост-ридинговых правок до итогов полигона, и
закон шва помечает эти флаги «гейчена 192». **Владелец снял это 28.08 (D39.165):** открыть дверь к
УЖЕ ПОСТРОЕННОМУ движковому механизму — не то же самое, что проектировать продуктовый цикл
пост-ридинга. **Гейченным остаётся цикл**: отдельная ручка «перегенерировать», `resnapshot --dry-run`,
доезд правки до ЧЕРНОВИКА через сид. Этого не строить.
## §3. Состав пака
### §3.1. Мина — ЗАКАЗ, форма свободна; чинить ПЕРВЫМ
**Заказано:** продолжающий прогон по книге, чей банк двигался, больше не падает на гарде снапшота.
**Что знать, прежде чем выбирать форму** (проверено мной, пере-проверь):
- `--resnapshot` принимает пере-привязку и пере-перевод затронутых юнитов. `--accept-rebill`
другое: он принимает ПЕРЕ-ПЛАТУ сверх порога. **Это ортогональные флаги**, и так сказано в самом
движке: `backend/cmd/tmctl/main.go:252` — «The three money flags are ORTHOGONAL». ⚠ Там же
предупреждение, которое тебя касается напрямую: `--ceiling-usd`НЕ бюджет прогона, он говорит
«книга может дойти до $X», а не «этот прогон потратит $X».
- ⛔ **ОДНОГО `--resnapshot` НЕ ХВАТИТ, и первая редакция промта здесь ошибалась (нашёл
опровергатель).** Отказ консент-гейта — ПЛОСКИЙ `fmt.Errorf` (`backend/internal/pipeline/rebill.go:322`),
а не типизированный отказ ⇒ `tmctl` выходит кодом **1**, и платформа запишет `failed` ПОСЛЕ взятого
холда. А порог низкий: `min($0.50, 5% × книги)`, и по замеру D39.165 десятиглавая книга стоит
$0.120.19 ⇒ порог около ПОЛУЦЕНТА. Правка частотного термина — имени героя, флагманский случай
§0 — почти гарантированно НАД порогом. **Дверь, передающая только `--resnapshot`, не сможет продать
ровно то, ради чего строится.** Значит согласие на СУММУ обязано доезжать тоже.
-**Носителя факта «банк двигался» СЕГОДНЯ НЕТего надо ПОСТРОИТЬ, и промт этого не скрывает.**
`ApplyBankCorrections` (`platform/internal/runs/bank.go:90-187`) в Postgres не пишет НИЧЕГО:
квитанция уходит звонящему и умирает. Носитель — твой предмет, зона твоя. ⚠ Его края назови сам и
проверь: превью (`preview`) и ответ `changed:false` фактом считаться НЕ должны · правка в окне
`awaiting_bank` относится к ТОМУ ЖЕ прогону · argv обязан быть СТАБИЛЕН при респавне попытки, иначе
флаг появится посреди прогона.
-**«Банк двигался» НЕ РАВНО «снапшот двигался только из-за банка», и это дыра в моём же условии.**
Снапшот на SaaS двигают и деплойные причины: промпты пары и langpack складываются в него
(`backend/internal/config/book.go:86,92` — «a pack edit is a loud --resnapshot»), то есть апгрейд
деплоя двигает снапшот ВСЕХ книг. На книге со свежей квитанцией банка условный `--resnapshot`
примет и ЭТОТ дрейф — а `repinnable` отвечает false для не-банковых сдвигов (`stagerun.go:94-95`),
значит юниты пойдут в пере-оплату, и под порогом — МОЛЧА. **Заказ: форма обязана различать
банковый сдвиг от деплойного либо делать согласие явным. Как — решаешь ты, но «свежая квитанция»
сама по себе основанием НЕ является.**
### §3.2. Дверь: допуск пере-прохода — ЗАКАЗ
**Заказано:** на книге, где остаток нулевой, но банк двигался после последнего прогона, старт
прогона ДОПУСКАЕТСЯ.
Сегодня он невозможен: шкала клампится остатком (`platform/internal/pgstore/books.go:969-973`,
`ChaptersLeft` «it clamps the ceiling scale»), у дочитанной книги `Scale` даёт `Max=0`, и любой старт
отбивается (`platform/internal/runs/runs.go:268-281`).
**Размер холда — думай отдельно, это деньги, и ломает он в ОБЕ стороны.** Завышенный: пере-проход
стоит ЦЕНТЫ (незатронутое идёт за $0), а холд в главах × $0.03 завысит его в разы. Заниженный:
`CeilingTemplate.Args` отказывает неположительному потолку (`platform/internal/runner/engine.go:64-69`),
а `--ceiling-usd` — КУМУЛЯТИВНЫЙ книжный кап (`spawn.go:187-213`, `bookCap`), поэтому холд обязан
остаться строго положительным ПРИРАЩЕНИЕМ к уже потраченному. Форма твоя; вариант «холд от сметы» —
§3.3.
### §3.3. Смета через шов — ЗАКАЗ на ФОРМУ, и здесь есть настоящий вопрос
Движок уже публикует смету в `status --json`: `rebill_units` и `rebill_usd`
(`backend/internal/pipeline/status.go:202-209`). Платформа их не берёт — **и это НАМЕРЕННОЕ
исключение аллоулиста** (`resync.go:10-13`).
**ПОПРАВКА К ПЕРВОЙ РЕДАКЦИИ ПРОМТА (нашёл опровергатель): `rebill_usd` через ШОВ пускать МОЖНО.**
Я ошибочно запретил это ссылкой на D39.84 — но D39.84 запрещает ПРОЕКЦИЮ денег в API-ответ и в
INFO-лог, а не пересечение шва. Деньги шов уже пересекают законно и хранятся:
`platform/internal/ingest/resync.go:31-37`, `Spend *money.MicroUSD` — «stored in the credit tables and
NEVER projected into an API response or an INFO log (D39.84)». D39.165 и строка 215 говорят про ОБА
поля. **Бери оба; наружу, в API, доллары не выпускай.** Без долларовой половины холд от сметы
невыразим — пер-юнитной цены у платформы нет вовсе.
**Мой довод про аллоулист — прими с проверкой либо опровергни:** `rebill_units` — СЧЁТ РАБОТЫ, той
же природы, что уже пересекающие шов `total_units`, `done`, `flagged`, `pending`.
**Но лёгким этот пропуск НЕ будет, и вот почему:** компаньон контракта в §2.12
(`docs/architecture/14-api-contract/README.md:505-511`) называет «ре-билл» В ЗАПРЕТНОМ СПИСКЕ
ПОСЛОВНО. Спор о природе счёта ратифицированного списка не снимает — значит показ юнитов
пользователю требует правки §2.12, и она входит в контрактную половину §3.4.
**Заказано:** пользователь до покупки видит, **сколько юнитов затронет** пере-проход. Это прямое
исполнение п.7 закона шва — проекция прежде мутации.
### §3.4. Контрактная половина — ОПИСАТЬ, НЕ ПРАВИТЬ
Опиши предложением в журнале, правлю я:
- фраза «finished work is not bought twice» (`openapi.yaml:590`) в нынешнем виде запрещает то, что
пак разрешает — нужна оговорка про пере-проход;
- поле «затронуто N юнитов» в ответе опций прогона;
-**правка §2.12 компаньона** — он держит «ре-билл» в запретном списке пословно, и без неё код
разойдётся с каноном (см. §3.3);
-**вопрос, а НЕ заказ: нужен ли проводу «вид покупки» вообще.** D39.165 ратифицирует показ
«затронуто N юнитов» и о видах покупки не говорит НИ СЛОВА. И не обосновывай открытый словарь
аналогией с `Progress.stage`: D39.163 запрещает такой довод буквально — «третьего исключения нет,
и „раз уж есть два“ аргументом не будет; каждое следующее — отдельная нота». Считаешь, что вид
покупки нужен, — приноси довод по существу, я заведу ноту.
### §3.5. Чего в паке НЕТ — пропуски подписаны
- **Ценообразование от объёма исходника** (D39.165 §1) — НЕ в этом паке. Оно гейчено калибровкой, а
калибровка — строкой **202** (живой прогон текущего стека). Константу $0.03 не трогать.
- **Потолок объёма в движке** — движковый предмет, не твой.
- **Эпоха смены формы конвейера** (`PD-403`/`PD-404`, D39.165 §2) — отдельный пак той же зоны, но
НЕ этот: он про счёт готовности, а этот про покупку. Не смешивать.
- **Доезд правки до ЧЕРНОВИКА** — гейчено полигоном, см. §0-бис.
## §4. Самопроверка ИСПОЛНЕНИЕМ — «перечитал сам» её не удовлетворяет
1. **Батарея зоны** под `-race` с живым Postgres, линтер 0 issues; числа — с командами.
**`TM_PLATFORM_TEST_DSN` ставить ОБЯЗАТЕЛЬНО:** без него значительная часть батареи уходит в
SKIP, а зелень рапортуется всё равно — ловушка, на которой приёмка уже ловила сдачу (D39.162).
**Число пропусков посчитай КОМАНДОЙ и приведи в отчёте** (с DSN и без) — константу из прошлого
пака сюда не переписывай, дерево с тех пор двигалось.
2. **Мина доказывается ПОСТ-ФИКСНЫМ инвариантом, и ⛔ НЕ на движке-заглушке.** Первая редакция этого
пункта была ВЫРОЖДЕННОЙ (нашёл опровергатель): у заглушки гарда снапшота нет вовсе, поэтому
«прогон дошёл до движка» зелено при ЛЮБОМ коде — это проверка argv в маскировке.
**Не-вырожденная форма существует и дешева:** живой `tmctl`, прецедент в твоей же зоне —
`platform/internal/runner/bankapply_live_test.go`. Гард достижим БЕЗ провайдерских ключей и без
единого платного вызова: без флага он стреляет ДО первого вызова модели, с флагом $0-репин
проходит. ⚠ И состояние обязано быть правильным: **edit-джоб существует ДО правки** — иначе
репро зелено без фикса (эррата 28.08-и).
3. **Дверь доказывается допуском:** на дочитанной книге с подвинутым банком старт ПРОХОДИТ, на
дочитанной книге без движения банка — по-прежнему отбивается.
4. **Свои посадки мутаций:** минимум по одной на пункт; вердикт — по ДЕЛЬТЕ против чистой базовой
линии и по ТОПИЧНОСТИ упавшего теста, не по цвету батареи.
5. **Субагенты РАЗРЕШЕНЫ явно.** Опровергатель на §3.3 (пропуск `rebill_units` через аллоулист) —
**ЗАКАЗ, не право**: он получает мой довод и мандат «покажи, где это нарушает §2.12 контракта или
D39.84». Веер соразмеряй предмету, численного потолка нет.
## §5. Оси ревью — 13, вправе заменить с аргументом
1. **Ось денег:** может ли пак купить больше, чем показал; может ли холд разойтись с фактом;
не превращает ли `--resnapshot` громкую ошибку в тихую покупку.
2. **Ось «пара, которой в репо нет»:** ветвления по паре/книге в Go быть не должно; вид покупки на
проводе — открытый словарь.
3. **Ось детерминизма:** трогаешь argv движка — не сдвинулись ли снапшоты и хеши так, что прогон
перекупается.
## §6. Записка-план, комплектность
**До правок** — записка-план в зонном журнале. **В конце** — таблица комплектности против §3: пункт →
что сделано → каким ИСПОЛНЕНИЕМ подтверждено. Слово вместо команды = пункт НЕ сделан.
**Журнал `docs/PROGRESS.md` — НЕ твой**, пиши только в зонный. (Оркестратор 28.08 унёс чужую
секцию своим коммитом ровно из-за общего окна записи — механизм плохой, не повторяй его с другой
стороны.)
## §7. Эхо-протокол старта
ДО работы — ≤10 строк: **скоуп · инварианты · не-делать**. Первое действие — вписать свой блок в файл
канала (§10), сразу второе — послать мне эхо.
## §8. Obstacle — обязательная секция
**«Что НЕ удалось и что НЕ проверено»** отдельной секцией, не россыпью.
## §9. Канал вопросов и твоё право отказаться
Конфликт промта с кодом или доками — **пинг, не интерпретация в свою пользу**.
**У тебя есть право сказать «этого делать не надо» — с аргументом.** Промт писал не тот, кто живёт
в этом коде. За последние сутки исполнители опровергли ДВА моих заказа и оба раза были правы; один
из них я пере-проверил своей посадкой и отозвал. Отказ с разбором дороже послушного исполнения.
**Тесты и гейты не подгонять под зелень** (D39.121).
## §10. Как со мной связаться
**Адрес — в файле `/tmp/textmachine-channel`** (механизм — `CLAUDE.md`). Впиши свой блок первым
делом, чужие не трогай. ⚠ **Канала нет ⇒ НЕ искать:** вопрос секцией в отчёт, работа продолжается.