textmachine/platform/docs/PLATFORM_P7_SESSION_PROMPT.md

163 lines
18 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.

# Промт: платформа, пак P7 — читающая поверхность по контракту 0.3.0 + модель ошибок + форварды (П-17, строка 169 единого)
> Выдан №17 16.08.2026, пересобран после лендинга батча 0.3.0 (D39.142144) и опровергателя промта.
> Запуск — по слову владельца.
## 0. Зачем
Платформа (control plane фронт↔движок) построена до потребительской половины шва: вход, кредиты,
раннер, интейк, ингест событий движка в Postgres. Из 20 операций контракта 0.3.0 отвечает на 8:
фронт не может читать главы/юниты/замечания/банк/поток — он на моках и ЗАМОРОЖЕН, экран подписи
строить не на чем; отказы — английской фразой без машинного кода. Твой пак делает платформу читаемой
и отказы машинными → разблокирует фронт. Контракт только что пере-согласован и сломан минором 0.3.0,
чтобы ты строил СРАЗУ по правильной форме — не по памяти о старой.
## 1. Нормативный источник
**Канон `docs/architecture/14-api-contract/openapi.yaml`, `info.version: 0.3.0`** (не та версия →
стоп, пинг). Зеркало `frontend/docs/api-contract/` ОТСТАЁТ намеренно (фриз фронта) — читать только
канон. Форма каждой ручки решена там; расхождение промта с каноном → верь канону и пингуй.
## 2. Зона и git
Ты не коммитишь — лендит оркестратор. Пишешь только в `platform/`; отчёт/вопросы — только
`platform/docs/platform-PROGRESS.md`. Чужие зоны read-only; живой полигон (`eval/`,
`docs/experiments/`) не трогать; `.env` не читать; git не трогать вовсе (ни `add`, ни `commit`, ни
`reset`/`checkout`), файлы застейдженными не оставлять. Путь Go-модуля не вкладывать под путь движка
(D39.85).
## 3. Читать (≤5)
1. Канон + компаньон (`docs/architecture/14-api-contract/`) целиком. В компаньоне: §3 таблица
«чтение → источник» · **приложение А-2 — готовая карта «твоя ветка `v0.go` → код ошибки» с
`file:line`** · §6б — почему формы такие.
2. `docs/research/28-contract-review.md` §8а (классы отказов) · §5б (сеть) · §9 (находки твоей зоны)
+ D39.138 п.2 и D39.142144 (хвост `docs/architecture/05-decisions-log.md`).
3. Свой журнал `platform-PROGRESS.md`: три пинга №17 + аддендумы (входы пака, `file:line` находок).
4. Read-out движка — пинг №15 там же: `<db>.manifest.json` (`tm-manifest-v2`; `unit.id =
<chapterID>:<cutTag>:<firstChunkIdx>`; ⚠ `heading` — ВРЕМЕННЫЙ рендер «Глава N», НЕ метка книги)
· `<db>.bank.json` · `<db>.bank-stop.json` (`conf: null` ≠ 0); пишутся атомарно, читать можно при
живом прогоне. Плюс своя `unit_resolutions` (миграция 00015).
5. `CLAUDE.md`; жаргон — `docs/glossary.md`.
## 4. Состав. Пункты 05 — «РОВНО так» (состав ратифицирован; формы внутри — твои, где канон/промт
их не фиксируют). Пункт 6 — судишь сам. Отложенное — только явно, списком в отчёте.
**0. Рантбук деплоя живым `migrate`, end-to-end, $0, первым шагом** (предусловие первого выката;
твой журнал: «живьём не гонялся»): прогнать свой `deploy/README.md` новым бинарём движка по книгам
стенда (`tmplatformctl books --migratable` → `tmctl migrate`). Попутно: `deploy/README.md:131` —
мёртвый текст ошибки (движок печатает `schema_mismatch found=N expected=M`, exit 13);
`cmd/tmplatformctl/runs.go:45` — комментарий зовёт голый `tmctl` из PATH (тихий no-op старым
бинарём); якорь П-1 в BACKLOG обновить.
**1. Форварды:** (а) читать `BookIntake.title` — сегодня игнорируется (`internal/httpapi/v0.go:369-376`);
по 0.3.0 обязателен, пустая строка = «назови по файлу»; (б) проецировать `reject_reason` — писатель
`pgstore/books.go:310`, проекция `projectBook` (`v0.go:470`; обоснование-комментарий `:497`) —
значениями словаря канона `RejectReason` (`processing_failed`, не имя внутренней ветки).
**2. PD-104:** `SignupGrantMicroUSD` дефолт → **0** + тест (слово владельца 16.08; возврат $5 — с
суточным потолком при платежах). Ветка «0 при неверифицированном email» (`login.go:306-308`) уже
есть — не баг. Протухшие «$5»: `PLATFORM_DIRECTION.md` §2, BACKLOG П-7, регистр.
**3. Модель ошибок — ПЕРВОЙ из контрактной половины** (от словаря зависят формы остальных ручек):
`Problem` по канону (`code` 16 корневых + `cause` + `request_id` из `internal/reqid` + `errors[]`).
Словарь НЕ выводить — реализуй карту А-2 компаньона; реальная ветка без кода → пинг, не изобретение.
Класс 2 = один код `content_refused`, без вариации, лимит попыток — по канону (`:2394`).
`WWW-Authenticate` на 401. Две причины 403 (нет `X-TM-Client` ≠ кросс-origin) — раздельно только в
открытом `cause.code`, корневой `forbidden` один (канон), новых корневых не заводить.
**4. Читающая поверхность (ядро):** `listChapters` · `listUnits` (только пер-главно; ручку «вся
книга юнитами» НЕ заводить — инвариант твоего же `PLATFORM_DIRECTION.md:208-210` и §5б; `410 Gone`
на исчезнувшую главу; `Unit.notes` массивом) · `listNotes` (`id`+`created_at`+обязательный
`chapter_id`; порядок `created_at`, тай-брейк серверный) · `listBankTerms` (проекция сайдкаров;
агрегаты `total`/`signed`/`pending_decisions`/`complete` — первая страница, ИНФОРМАЦИОННЫЕ) ·
`submitBankDecisions` (`approve`/`decline`, накопительный, `maxItems` 1000; неизвестный `term_id` →
400 всей пачки, item-код `unknown`) · дельта-чтения `?after_version=` на notes/bank (ВКЛЮЧИТЕЛЬНЫЕ;
водяной знак = наименьшая ревизия обхода; устаревший → 400 `version_too_old`) · **SSE
`streamBookEvents`** — все правила в каноне: `id` = позиция истории книги (служебные кадры несут id
последнего кадра, `0` на пустой книге), кадр `end` + `204` по `Last-Event-ID` (кадра «конец
разбора» НЕТ — конец интейка = смена статуса), склейка только state-кадрам, `note` не терять в
пределах соединения, `resync_required` когда не можешь продолжить с предъявленного id ·
**`structure_version`** — в `Book`, во всех четырёх конвертах страниц и в КАЖДОМ кадре
(`EventBase`); источник — манифест движка · **gzip** на JSON (НЕ на SSE) + **ETag/If-None-Match →
304** на всех коллекциях, КАРТОЧКЕ книги и `/capabilities`; валидатор — ко всему запросу, query
включая (`:850` канона; «ETag = ревизия страницы» НЕДОСТАТОЧЕН — стр.2 и дельта той же ревизии
обязаны отличаться).
⚠ Ловушки, каждая — канон против сегодняшнего кода:
- **`heading`:** канон запрещает класть рендеренный порядковый (`:1556-1566`) — а `heading`
манифеста ровно он; проецируй `null` до движковой строки 160. Прямая проекция сайдкара =
нарушение.
- **Гейт полноты банка УЖЕ ПОСТРОЕН — ДЕМОНТИРУЙ:** `internal/runs/reconcile.go:934-938`
(`awaiting_bank` → `ErrNotResumable "glossary is not signed"`) ссылается на снятые D39.144 разделы.
Подпись = ОДИН resume при любом состоянии решений; полноту не отливать ни в новый код, ни
оставлять в старом. Границу паузы движка сверь чтением его кода (строка 191); расхождение — пинг.
- **Пофазность у главы НЕ строить** (К-10 «НЕТ», D39.138 п.5): колонки `units_draft_done/edit_done`
лежат готовыми и напрашиваются — глава отдаёт ОДИН счётчик прохода по канону.
- **`Note.code`:** словарь НЕ ратифицирован (приложение А — заготовка ◆). Бери коды из ◆-карты как
есть, новых не изобретай; причина движка мимо карты → пинг.
**5. Конформность ПОСТРОЕННОГО. Правило: пофайловый дифф каждой построенной wire-структуры против
required-списка канона; расхождение — чинить или в отчёт с причиной.** Именованный минимум:
`Progress` переезжает с книги на `Run` (одна полоса в ГЛАВАХ до остановки, знаменатель — купленный
объём) · `Book`: +`revision`, +`chapters_done` (SQL уже считает — `pgstore/books.go:677-681`),
`progress`, **`genre`** (`v0.go:108` — нарушение allowlist-инварианта канона, строка 184) ·
`Run`: +`book_id`, +`failure_reason` (словарь канона из трёх значений — мапь полосу 1019 и ветки
`outcome()`), `verify_bank`→`stop_for_signing` (провод: `v0.go:127,154`) · `Usage`:
`paused_reason`→`halt_reason` со СВОИМ словарём `AccountHaltReason` (`v0.go:159-163` сейчас несёт
прогонный) · `GET /capabilities` — НОВАЯ ручка и зависимость всех чтений (дефолты страниц читаются
из неё; все шесть полей канона, `intake_enabled` включая) · `limit`: подрезать до 1000, НЕ отвергать
(`pgstore/books.go:510-511` сейчас сбрасывает к дефолту; схемную валидацию параметра вывести из-под
отказа — `:886` канона) · трейлинг-части интейка → 400 (⚠ меняет узаконенное 0.2.3 «молча теряется»
— по канону 0.3.0) · `Location` на 201 · `Idempotency-Key` на `createBook` И `startRun` — семантика
целиком в `§IdempotencyKey` канона · `blocked {code, book_id}` на run-options и 409 (таблица
`reservations` знает держателя) · отказ по неподдерживаемой паре кодом на интейке · `finalizing` —
вон из словарей валидации (`internal/runs/runs.go:229`, `pgstore/sink.go:435`; CHECK-констрейнты —
по канону, значение никем не пишется).
**6. Свой регистр — судишь сам, кроме помеченного РОВНО:** РОВНО — статусы PD-172/173/174/180
(исполнены 0.2.3) и PD-199 (закрыт D39.132 п.2а) привести; строку PD-201 обновить (движковая
половина финальна — самолечение «exit 13 → migrate → повтор» можно строить); **PD-241 исполнить —
ратифицирован D39.132 п.2д «следующим касанием зоны», это касание — ты** (намерение стопа выигрывает
на статусе). Судишь: кандидаты PD-219/PD-217/PD-162; находки §9 research/28 — каждой диспозицию
(берёшь / P8 / отклоняешь, с причиной): висящие расчёты без бюджета холда · флаг аккаунта сканом
всех книг · `ReadRunForSpawn` O(живых) · `/metrics` без аутентификации · лимитер входа на процесс ·
сырой Go-текст в карантине. Протухшие тексты зоны: `PLATFORM_DIRECTION.md` §3-баннер (снят D39.132
п.2б), §4 п.5 (склейка сузилась), **`:199` «подписывает банк частями» — ложь после D39.144**, §2
«$5». Инструменты: **sqlc — привязан к паку** (D39.132 п.2б; `overrides` на денежные типы;
отступление = пинг); oapi-codegen — кандидат, реши и аргументируй.
**Отложено в P8 (не тихо):** `updateBook`/`deleteBook`/`getRun` · **`createExport`/`getExport`**
(содержимое — S7; формы в каноне финальны) · эскроу П-18. Всё прочее невлезшее — списком с
причинами.
## 5. Нормы
- Самопроверка исполнением: `make check` + ОБА гейта (`TM_PLATFORM_TEST_DSN`,
`TM_PLATFORM_TEST_ENGINE_BIN`/`_BOOK_TEMPLATE`), **скипов 0 — гейт** (неустранимый скип =
obstacle с объяснением); дифф `^func Test` исполнением; живые пробы новых ручек на дев-стенде
(сид P6).
- Заявление = команда: каждое число/категорика отчёта — с командой; приёмка пере-ранит.
- Записка-план по §4 (пп. 06 + отложенные): «исполнено, где / отказ, почему» на каждый; сдача =
все с диспозицией.
- Шов: касаешься канала движка → сначала инвентарь ВСЕХ его каналов и кодов чтением чужого кода
(урок D39.132).
- Посадки мутаций — `ENGINEERING_STANDARDS.md` §3, списочный пункт «посадки» (~:67-69; заголовка
«§3.3» в файле нет).
- Предметная ось: индустриальный первоисточник прежде велосипеда — RFC 9457 · WHATWG SSE ·
RFC 9110/9111 (условные запросы, `Vary` при gzip). Право заменить ось — с аргументом.
- Деньги: пак их не двигает (PD-104 — константа); коснулся — два независимых пути счёта из сырого
леджера.
- **Адверсариальное селф-ревью финалом — механизмом (субагенты РАЗРЕШЕНЫ, спавнь):** ≥2 независимых
ревьюера по финальному диффу, author≠reviewer: (а) контракт-конформность — канон против твоих
ручек, пере-раном живых проб; (б) деньги/шов — свой инвентарь каналов, не твой список. Плюс СВОИ
посадки в новые гейты/ручки (не из ожидаемого тобой списка). Артефакт: таблица находок/посадок с
диспозициями; ноль находок = не верить прогону.
- Obstacle reporting — обязательная секция: что НЕ удалось / не проверено.
- Канал вопросов: непонятно / промт против кода-спеки-доков → пинг через владельца, НЕ
интерпретация. Право «этого делать не надо» — с аргументом.
## 6. Старт и сдача
Эхо-протокол: первым деливераблом ≤10 строк «скоуп / инварианты / не-делать». Сдача: отчёт в
`platform-PROGRESS.md` (записка-план · команды · живые пробы · таблица селф-ревью · obstacle ·
диспозиции §4.6), дерево незакоммиченное, регистру — строки по находкам. Без саги.