textmachine/docs/PLATFORM_P12_SESSION_PROMPT.md

268 lines
32 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.

# Промт: платформа, пак P12 «долги под ногами» — семь открытых major и висящие обязательства зоны
## 0. Какая проблема и что решит твой результат
У зоны нет активной стройки, но регистр держит **7 открытых major** — и почти все они про ДЕНЬГИ или про
ЛОЖЬ экрана: запись о правке банка теряется навсегда при обрыве клиента (`PD-425`), экран показывает
«готово» по чужому прогону, пока живой тратит деньги невидимо (`PD-402`), смена состава волн на живой
книге продаёт уже переведённые главы повторно (`PD-403`/`PD-404`), полоса стоит на нуле всю жизнь
прогона (`PD-405`), намертво заблокированная расплата невидима и не выводится ничем, кроме Stop
пользователя (`PD-424`). Плюс обязательство, висящее с 27.08: обход `--verify-bank` так и не снят,
хотя движковая половина порядка D39.158 давно залендена. **Что решит твой результат:** деньги перестают
теряться молча, экран перестаёт врать, зона входит в живой прогон (очередь №20 п.23) без известных мин.
**Чего пак НЕ решает:** дверь выдачи `createExport`/`getExport` (пинг №20 в зонном журнале — она ждёт
живого прогона) · `PD-410` (единица продажи — ОТДЕЛЬНЫМ паком, слово оркестратора 28.08, тело решения —
D39.165 §1) · эскроу П-18 · перф-строки `PD-412`/`PD-413`.
## 1. Зона записи и git
Пишешь только в `platform/`. **Не коммитишь**: дерево готовишь и передаёшь оркестратору. Канон git — в
`CLAUDE.md`. ⚠ Одна операция выходит за код зоны и разрешена явно: `tmctl migrate` по СТЕНДОВЫМ книгам
зоны свежесобранным бинарём (§3.7) — это операция над данными стенда, не правка `backend/`.
## 2. Карта чтения — ПЯТЬ позиций, дальше только по их ссылкам
1. `platform/docs/ENGINEERING_STANDARDS.md` — целиком; **DoD §3 — закон** (каждый его пункт исполняется
буквально, отступление = пинг).
2. `platform/docs/STACK_DECISIONS.md` — разделы «Гейты батареи» (единственный носитель условий) ·
рецепт стенда · §35 (монотонность `edit_wave` — правило, которое этот пак пере-подписывает).
3. `platform/docs/DEFECT_REGISTER.md` — шапка/легенда + ТЕЛА адресуемых строк: `PD-425 402 403 404 405
424 418 411 369 420 431 432 427 203 367 422 213 423 380 44`.
4. `platform/docs/platform-PROGRESS.md` — пинг №20 (30.08) и **ПИНГ №21 (27.08, D39.158)** — носитель
обязательства по обходу `--verify-bank` и СОСТАВА снятия (подавление флага при возобновлении +
особый случай в спавне + персистентная колонка `bank_released`); вопросы sqlc-сессии.
5. `docs/architecture/05-decisions-log.md` — ТОЛЬКО тело `D39.165` (греп `^## D39.165`), §2 «эпоха» —
источник решения владельца для §3.2; остальной журнал не читать.
## 3. Работа
**Порядок при нехватке ресурса (ранжирование оркестратора):** first-class — §3.1 (деньги, теряемые
молча) · §3.7 (обязательство, висящее с 27.08) · §3.3 (вход в живой прогон очереди №20); вторым
эшелоном — §3.2 (вскроется конфликт с каноном — пинг, и пункт уезжает СЛЕДУЮЩИМ паком, не молчаливая
отсрочка) · §3.6+§3.9 (дёшевы, тем же деревом); §3.4/§3.5/§3.8 — по остатку ресурса. Всё невзятое —
диспозицией строкой в записке-плане §6; честная резка с доводом лучше молчаливой каши.
### 3.1 `PD-425` — обрыв клиента теряет запись о правке банка навсегда (деньги, делай РОВНО так по классу)
Дверь коррекций пишет пост-verb факт (`RecordBankMove`) на контексте ЗАПРОСА (`internal/httpapi/bank.go:149`=`ApplyBankCorrections`):
клиент закрыл вкладку до ответа — запись не легла, `bank_moved_at` NULL навсегда, второго писателя и
свипа нет; дальше обычный прогон допускается без `--resnapshot` и умирает на снапшот-гарде движка ПОСЛЕ
взятия холда. Средство «503, пере-шли документ» недостижимо — клиента уже нет. **Класс лечения зона
назвала сама и уже дважды применила:** `WithTimeout(WithoutCancel(ctx), …)` —
`platform/internal/httpapi/idempotency.go:151`=`WithoutCancel` (`settleCtx`; комментарий `:147-149` — дословно
про обрыв клиента) и `internal/books/books.go:205,215`=`writeCtx` (тело — `internal/books/parse.go:271-272`=`WithoutCancel`).
⚠ Тело `PD-425` в регистре несёт БИТЫЙ якорь `pgstore/idempotency.go:150`=`Location` (там чтение ключа, detach нет) —
пере-нацель его той же правкой регистра (гигиена §3.9). Делай тем же классом; деталь (таймаут, что именно
накрывается) — реши сам и аргументируй. Пины свои: посадка «контекст отменён между verb и записью» обязана
красить дефект и зеленеть с фиксом.
### 3.2 `PD-403`/`PD-404`/`PD-411`/`PD-405` — полоса и повторная продажа глав. РЕШЕНИЕ ВЛАДЕЛЬЦА ДАНО — исполняй, не пере-решай
Строки стоят «лечение за решением владельца» — **решение дано 28.08, D39.165 §2, релей дословный:**
смена формы конвейера (добавили/убрали редактора) — **СОБЫТИЕ КНИГИ, как пере-нарезка, и счёт легально
пересчитывается** при пересечении границы; канон уже открыл дверь («never moves backwards WITHIN one
`structure_version`; cutting the book again recomputes both numbers» —
`docs/architecture/14-api-contract/openapi.yaml:1554-1558`=`never moves backwards`; ⚠ якорь D39.165
`1542-1545` дрейфанул — там сейчас RejectReason), нового исключения не изобретать. ⚠ **Носитель границы
эпохи нотой НЕ решён — реши сам и аргументируй** в рамках: флаг монотонен (пин D39.153 §4б) · форму НЕ
читать с последнего прогона · счёт пересчитывается только на СОБЫТИИ. Цена обеих дорог: пересчёт БЕЗ
движения `structure_version` нарушает букву канона на направлении «вниз»; движение `structure_version`
инвалидирует курсоры/идентификаторы пар/окна термов (`openapi.yaml:1233-1236`=`moves when the book is cut`).
Если выбранная форма требует правки ФРАЗЫ канона (второе событие пересчёта рядом с пере-нарезкой) — это
контрактный минор через ратификацию оркестратора: пинг ДО стройки, прецеденты миноров 0.7.0/0.8.0 есть.
При этом:
- ⚠ **Монотонность флага (D39.153 §4б) НЕ отменяется** — пин стоит, правка пина под зелень запрещена
(D39.121). Меняется другое: пожизненный счёт книги перестаёт выводиться из ЖИВОГО флага.
- ⚠ Ложный док-комментарий `recordWaveShape` — `internal/pgstore/sink.go`, греп `Monotone in one direction`
(⚠ номера строк сняты 30.08: файл правит эта же сессия; редакция D39.165 писала `405-408`, аудит нашёл `406-409` — дрейф) — переписать/снести целиком вместе
с правкой поведения, не механически диапазон строк.
- ⛔ **Заново НЕ предлагать** четыре отвергнутые формы: счёт всегда по редакторской волне · читать форму
с последнего прогона · немонотонный флаг · «какая фаза считается» как вопрос клиенту.
- **§35 `STACK_DECISIONS.md` пере-подписать** той же работой — это правка ЗАПИСАННОГО правила зоны, не
только кода; прежняя формулировка остаётся в истории с датой и причиной.
- **`PD-411`** — мёртвые `runs.draft_done/draft_total/edit_done/edit_total` (два писателя, ноль
читателей): запрет сноса был пер-паковым (P9); теперь снос миграцией — естественная часть этой же
правки. Реши сам, этим ли паком; если нет — диспозиция строкой.
- **`PD-405`** — прогон над книгой без материализованного дерева читает 0/total всю жизнь. Зона назвала
два лечения: отказ старта до дерева ИЛИ полоса из progress-событий. Выбери и аргументируй; ложный
комментарий `sink.go:219` снести.
### 3.3 `PD-402`, read-половина — экран не смеет показывать «готово» по чужому прогону (делай РОВНО так)
Write-гард уже закрыт (F12, `ErrNotResumable`, пин `TestAnOlderRunCannotBeResumedOverANewerOne`);
осталась read-половина: `lastRun` берёт `order by started_at desc` — живой прогон обязан иметь приоритет
над финишировавшим в карточке/полосе. ⚠ У `lastRun` ДЕСЯТЬ мест склейки на 30.08 (десятое —
`pgstore/runs.go:132`=`lastRun`, добавлено 28.08 ПОСЛЕ счёта «девять» из PD-44; пере-сочти сам грепом паттерна
склейки, не голым словом — голое ловит комментарии) и он в ⛔-зоне sqlc — правка судится СВОИМИ тестами
по каждому месту, не «зеленью батареи».
### 3.4 `PD-424` (+`PD-418`) — намертво заблокированная расплата обязана быть видимой и выводимой
Живой прогон с блокированной расплатой: `reopen` → вердикт `deferred` → `return nil` + `ClearRunDeferral`,
счётчик не растёт никогда, холд заморожен, не видит ни одна поверхность `PD-385`, `run abandon` не берёт.
**Приор зоны (опровергается аргументом):** `deferred` ⇒ `established=false`, блокированный расчёт =
неудача владеющей фазы. `PD-418` (settling живого прогона без ручки) — тот же узел: реши, закрывается ли
он той же правкой, и подпиши диспозицию.
### 3.5 `PD-369` (=П-21) + `PD-420` — легитимный запрос не имеет права получать 500
Конкуренция на одном ключе идемпотентности: `claimRounds=3`, 8 гонщиков отбирают гонку трижды → 500.
Зона назвала две формы: граница по ВРЕМЕНИ либо явный `ErrKeyInFlight` → контрактный ответ. **Слово
оркестратора: 500 на легитимном запросе недопустим; между двумя формами выбери сам и аргументируй**
(учти словарь кодов контракта — новый код = вопрос, маппинг существующих — нет). `PD-420` — тот же узел
(её диагноз НЕ установлен): порядок — СНАЧАЛА фикс `PD-369` (форма `ErrKeyInFlight` зеленит тест по
построению — он этот error уже принимает), ПОТОМ пере-замер серией (≥80 итераций + параллельные батареи);
флейк пережил фикс — тогда изоляция/скип с диагнозом строкой в регистр; скип ДО фикса — снятие пина, не
вариант (D39.121). Вердикты посадок — по ДЕЛЬТЕ и топичности (DoD §3), красная чистая копия не маскирует
дельту.
### 3.6 `PD-431` + `PD-432` — честность носителей (делай РОВНО так)
- `PD-431`: `Touch` (`internal/pgstore/sessions.go:49`=`func (s *Store) Touch`) выбрасывает `RowsAffected` — апдейт в ноль строк
неотличим от успеха, скольжение окна бездействия не проверяет ни один живой тест. **Слово
оркестратора: поведение НЕ менять** (ноль строк — законная гонка с отзывом); лечение — честность
проверки: запинить скольжение окна СКВОЗНЫМ тестом через `auth.Authenticator` с живым
`*pgstore.Store` (сегодня их не связывает ни один тест). Если по ходу увидишь, что и поведение
требует слова, — пинг, не правка.
- `PD-432`: рецепт гейтов батареи в `STACK_DECISIONS.md` не говорит, что движковый бинарь стенда надо
ПЕРЕСОБИРАТЬ из текущего `backend/` — допиши строку рецепта (свой док зоны; протухший `tmctl` даёт
три красных теста «field … not found», читающиеся как дефект зоны). **Той же док-правкой:**
команда-проверка четвёртого условия батареи (`cut -d: -f3 /proc/self/cgroup` ≠ `/init.scope`) УЖЕ
стоит в «Гейтах батареи» и ОПРОВЕРГНУТА второй точкой `PD-423` (ложный отрицательный: тест зелен 5/5
при `/init.scope`) — сними её или пере-подпиши как опровергнутую со ссылкой на `PD-423`; прежняя
формулировка остаётся в истории с датой и причиной. Замену-кандидата (`cgroup.subtree_control`
целевого среза) можно назвать только КАНДИДАТОМ — диагноз `PD-423` не установлен, строке дай
диспозицию, не закрытие.
### 3.7 Снятие обхода `--verify-bank` — довести порядок D39.158 до конца (делай РОВНО так)
Порядок односторонний и записан: движок первым (залендён 27.08) → `tmctl migrate` по КАЖДОЙ книге →
только потом платформа снимает обход. Сделай: пересобери `tmctl` из ТЕКУЩЕГО `backend/` → `tmctl
migrate` по каждой стендовой книге зоны → сними обход в коде → живой пробой на стенде: стоп банка
доезжает флажком движка, а не обходом.
⚠ **Той же работой закрывается строка бэклога 240 (находка Д3 ревью P9, двое суток без носителя): оплаченный стоп подписи исчезает МОЛЧА** — рестарт проходит границу банка насквозь, а гард `LiftBankStop` писан против движка ДО памяти v16 и этот путь не держит. Реши ОДНОЙ работой: снять гард вместе с обходом ЛИБО доказать живой пробой, что память `bank_stop_presented` (схема v16) делает его недостижимым; молчаливо оставить как есть — нельзя.
**Состав снятия — по пингу №21, он ШИРЕ спавна:** (а) особый случай в спавне —
`platform/internal/runs/spawn.go`, греп `BankReleased` (⚠ номера строк здесь НЕ ставим: файл правит эта же сессия) — снять РОВНО; (б) писатель `LiftBankStop`
(греп `LiftBankStop` по `internal/runs/reconcile.go` и `internal/pgstore/runs.go` — номера строк двигаются под твоей же правкой) и (в) колонка `bank_released` с читателями
полосы (греп `bank_released` по `internal/pgstore/readmodel.go` — номера строк двигаются под твоей же правкой) — реши сам, этим ли паком: снос = НОВАЯ миграция (00016 не
править) + пере-вывод сегмента полосы; (б)/(в) сцеплены — снять писателя, оставив колонку, значит
заморозить `bank_released=false` и врать полосой (ось §5); не этим паком — диспозиция строкой, как у
`PD-411`. ⚠ **Снимаемое поведение ЗАПИНЕНО:** `TestAResumedRunIsSpawnedWithoutTheSigningStop`
(греп `TestAResumedRunIsSpawnedWithoutTheSigningStop` по `platform/internal/runs/reconcile_test.go`; его же комментарий — «Mutation caught: passing l.VerifyBank unconditionally», т.е. ровно заказанная правка). **Пере-подпись этого пина заказана этим
промтом** — как в §3.8: заказанная смена контракта, не подгонка под зелень (D39.121); пере-подписанные
пины перечисли поимённо. Той же работой уходят обоснования сброса флага из фикс-раунда 28.08 (строка F10,
`platform-PROGRESS.md:1467`): комментарий `spawn.go:159-169` («the owner's model») и док-коммент теста —
оба описывают поведение, которое пинг №21 объявил лишним. Если найдёшь причину, по которой снимать рано, —
пинг с уликой, не молчаливая отсрочка.
**Стенд УЖЕ СТОИТ** — второй по рецепту НЕ заводить: `~/.local/share/tmstand` (стендовая книга одна —
`books/bk_WIUSGBQTIGWE4ZBY`; бинари в `bin/`, `tmctl` — `~/.local/bin/tmctl`); `W=~/tmstand-work` в
рецепте — шаблон. Живой `tmplatformd` — демон ЗАКРЫТОЙ сессии оркестратора №19: убей по PID (⚠ не
`pkill -f` — инцидент P11) и подними свой свежесобранный. Для живого пробоя $0-пары подними СВОЮ
заглушку на `127.0.0.1:11434` (образец — `platform/internal/runner/translate_resnapshot_live_test.go:41`=`Listen`;
ollama на хосте нет) и ⚠ гаси её на время `make check`: тест второго гейта при занятом порту скипается,
а требование — скипов 0.
### 3.8 `PD-367` — интейк не принимает манифест, который свой же материализатор отверг бы (решение оркестратора)
Сегодня `{ChaptersTotal:120, пустой список}` заводит книгу, по которой можно СТАРТОВАТЬ И ОПЛАТИТЬ
прогон. **Решено: пол самосогласованности — симметричный, интейк отказывает** (закон шва: незнакомое/
несогласованное → не-деструктивно и громко). Это ПРАВКА ЗАПИНЕННОГО контракта интейка — расширение
заказано этим промтом, правки пинов перечисли поимённо в отчёте (это не «подгонка под зелень», это
заказанная смена контракта; сомнение — пинг). Батарея интейка ездит на документах без списка глав —
фикстуры расширь, не обходи. Смежную `PD-213` (незнакомая версия манифеста ведёт к УДАЛЕНИЮ файла)
реши тем же классом «незнакомое → не-деструктивно» или подпиши диспозицию строкой.
### 3.9 Гигиена регистра (дёшево, тем же деревом)
Закрыть `PD-427` (комментарий уже исправлен 29.08 — акт закрытия) и `PD-203` («предложено закрыть» ещё
P8-REVIEW; проверь предикат и закрой либо оспорь) · перенести `PD-380` и `PD-44` (обе fixed) из-под
чужих заголовков «Открытые» · завести строку на НЕПОКРЫТУЮ гоночную ветку `errIdentityRace`
(`pgstore/identity.go:99-113`=`race` — ретрай при `on conflict … do nothing`, гонка двух первых логинов одной
новой identity; ни один тест её не касается, все тестовые вызовы последовательные) с диспозицией:
запинить конкурентным тестом ЛИБО доказать недостижимость; ⛔ снос — только с доказательством: ветка
обслуживает ЛЕГИТИМНУЮ гонку логина, её снос = 500 на легитимном пути (класс §3.5) · **пере-диспозиционировать `PD-403` и `PD-410`**: обе несут «лечение за решением владельца/оркестратора», хотя D39.165 §2/§1 дали направление ещё 28.08 — регистр отстаёт от D-лога, и следующий читатель понесёт владельцу уже отвеченное · `PD-422` НЕ
трогать (гейчена проводкой `--max-units`, гейт оркестратора) — просто не забудь её в грепе по своим путям.
### 3.10 Границы
- ⛔ `backend/` не трогать (исключение — операция §3.7); ⛔ дверь выдачи не строить; ⛔ эскроу не строить;
⛔ `PD-410` не лечить (отдельный пак).
- ⛔ `observe.go` под sqlc не конвертировать, схему River в sqlc-конфиг не добавлять; склейки/read-модель —
⛔-зона sqlc; выпущенные миграции не править (append-only; новые — можно).
- Новая зависимость = строка в `STACK_DECISIONS.md` с датой и «зачем», ратифицирует оркестратор; Redis/ORM/
OTel — записанные «нет».
- Деньги: суммы не на провод/UI/INFO/метрики (D39.84); леджер append-only держит код.
## 4. Самопроверка ИСПОЛНЕНИЕМ (без неё работа не принята) — DoD §3 стандартов зоны, поимённо
- **`make check` целиком** при ТРЁХ гейтах + условии хоста (носитель условий — `STACK_DECISIONS.md`
«Гейты батареи»); скипы считать КОМАНДОЙ и называть вслух; зелень = полный список пакетов + 0 FAIL.
⚠ Статус четвёртого условия НЕ выводить из команды `/proc/self/cgroup` — она уже опровергнута второй
точкой `PD-423` (ложный отрицательный) и пере-подписывается в рецепте по §3.6; суди по самому тесту
(`TestARunIsBoundedByItsOwnCgroup` зелен при 0 скипов); красный — сначала проверь среду
(`cgroup.subtree_control` среза, рецепт в `STACK_DECISIONS.md`), потом ищи дефект.
- **Стенд:** пересобрать ВСЕ ТРИ бинаря, включая `tmctl` из текущего `backend/`; демона убивать ПО PID
(⚠ не `pkill -f` — инцидент P11); `pipeline-zero` для второго гейта; `curl --noproxy '*'`; правил
миграцию — пересоздай базу.
- **Мутационные посадки — в КОПИИ дерева ВМЕСТЕ с каноном** (`cp -a --parents platform
docs/architecture/14-api-contract <куда>/`); вердикт по ДЕЛЬТЕ против чистой базы ТОЙ ЖЕ копии и по
ТОПИЧНОСТИ упавшего теста, не по цвету. Каждое заявленное свойство несущего пути — запинено тестом,
ловящим мутацию; в отчёте назови, какой тест что пинит.
- **Греп ОТКРЫТЫХ строк регистра по СВОИМ файлам ПОЛНЫМИ путями** — каждое совпадение получает
диспозицию; якорь, убитый твоим переездом, чинишь ты.
- Находки — строками в регистр ТЕМ ЖЕ деревом; правки чужих до-паковых тестов — поимённо.
- ⛔ Тесты/голдены/гейты не подгонять под зелень (D39.121); несогласие — пинг.
- **Дифф `^func Test` — исполнением**; интервальная самоверификация субагентом в середине пака.
- **Разрешаю субагентов**; модель задавай явно; трудный вопрос — старшей модели.
- ⚠ **Адверсариальный проход по СВОЕЙ готовой работе перед сдачей.** Направления: деньги, теряемые между
verb и записью; экран, который врёт при гонке живого и финишировавшего; пересчёт счёта, продающий
купленное; 500 на легитимном пути; зелёный тест, не проверяющий ничего (класс D39.171). Пока идёт
проход — дерево не двигается: морозь или называй агенту коммит.
## 5. Оси ревью
**Деньги** (ни одна запись о деньгах не теряется молча; сверка леджера двумя путями) · **честность
экрана** (полоса/карточка не врут ни при гонке, ни при смене формы) · **контрактное поведение**
(интейк/идемпотентность/окно сессии отвечают то, что обещано, и это запинено). Вправе заменить ось с
аргументом.
## 6. Записка-план и комплектность
До кода — записка-план в `platform/docs/platform-PROGRESS.md`: что берёшь, что не берёшь, чем докажешь;
числа — свои, командами, не унаследованные из промта. Перед сдачей — механическая сверка состава против
§3 таблицей: пункт → сделано/нет → чем доказано. Пропуск подписывается пропуском. **Последний абзац
отчёта оказался планом или обещанием? Сделай сейчас.**
## 7. Канал вопросов и право отказаться
Конфликт промта с кодом/доками/регистром — **пинг через владельца, не интерпретация**. Есть право
сказать «этого делать не надо» с аргументом (по любому пункту §3 — состав большой, честная резка с
доводом лучше молчаливой каши).
⚠ Правки задания по ходу работы доезжают ТОЛЬКО релеем через владельца — отдельным его сообщением. Что
не пришло релеем — не заказ. Полученную правку эхо-подтверди и вынеси отдельным пунктом отчёта.
## 8. Заявление = команда
Любое число и категорика — с командой получения; приёмка пере-ранит, клейм без пере-прогона = «со слов
сессии». Утверждение без `file:line`/замера помечай словом «мнение».
## 9. Эхо-протокол старта
ДО первой правки — ≤10 строк: скоуп / инварианты / чего не делаешь. Отправь первым действием по адресу
оркестратора из `/tmp/textmachine-channel` (механизм — `CLAUDE.md`; впиши туда СВОЙ блок первым делом).
**Канала нет ⇒ НЕ искать**: вопрос секцией в отчёт, работа продолжается.
## 10. Obstacle reporting
Обязательная секция: что НЕ удалось и что осталось непроверенным. Пустой не бывает. Три исхода:
«подтверждено» / «опровергнуто» / «не проверено» — третье не сваливать во второе.
## 11. Журнал
Записка-план, итоги и вопросы — ЗОННЫЙ `platform/docs/platform-PROGRESS.md` (в `docs/PROGRESS.md`
платформа не пишет).