textmachine/docs/CONTRACT_BATCH_SESSION_PROMPT.md

203 lines
29 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.

# Промт: сессия БАТЧ 0.3.0 — ломающая правка контракта API v0 по принятому ревью (строка 183)
> Выдан оркестратором №17 16.08.2026 по ратификации D39.138 (приёмка контракт-ревью research/28;
> решения владельца 16.08 — его §8). Исполняет ОТДЕЛЬНАЯ сессия со своим онбордингом (норма D39.120 п.2).
> Запуск — по слову владельца.
## 0. Какую проблему ты решаешь и что решит твой результат
Проект — SaaS-перевод книг: движок (Go, `backend/`) ↔ платформа (control plane, `platform/`) ↔
веб-фронт (`frontend/`). Между фронтом и платформой стоит ратифицированный контракт **API v0**
(OpenAPI 3.1). Он рос точечными правками 0.2.0→0.2.3 под давлением строек, и целостного ревью не
имел. 1516.08 отдельная сессия провела такое ревью (`docs/research/28-contract-review.md` — ПРИНЯТ,
D39.138): ядро контракта здорово, дефекты сосредоточены там, где контракт писался вперёд без
потребителя — ошибки, поток, экспорт, замечания, глава. Владелец разобрал доклад вопрос-за-вопросом
и принял решения (§8 отчёта); оркестратор ратифицировал их нотой **D39.138 п.2**.
Твоя работа — **исполнить эти решения правкой спеки**: батч 0.3.0. Момент дешёвый и не повторится:
**платформа не отвечает на 8 операций из 16** (сервера за ними нет вовсе, а фронт заморожен и живёт
на моках), поэтому правка их формы сегодня стоит только правки документа. Сразу после тебя платформа строит читающую
поверхность (пак P7) **по твоей спеке** — каждый пропущенный тобой дефект она отольёт в код, миграции
и воркер, где он подорожает на порядок. Отнесись к каждой форме ответственно: этот документ — закон
для трёх зон.
## 1. Зона и git (читать ДО первой правки)
**Ты не коммитишь — лендит оркестратор.** Твоя зона записи — РОВНО три файла:
1. `docs/architecture/14-api-contract/openapi.yaml` — нормативная спека (канон);
2. `docs/architecture/14-api-contract/README.md` — компаньон (правится ВМЕСТЕ со спекой, §5 ниже);
3. `docs/archive/reports/CONTRACT_BATCH_0.3.0_REPORT.md` — твой отчёт (новый файл).
Всё остальное — read-only: код трёх зон читать можно и нужно, править нельзя. **Зеркало
`frontend/docs/api-contract/openapi.yaml` НЕ трогать** — зона фронта заморожена (D39.136 п.2), зеркало
синхронизируют лендинг и первое касание зоны; временное расхождение канона и зеркала — известное
состояние, не дефект (ратифицируется при лендинге). Чужие незакоммиченные файлы в дереве (живой
полигон: `eval/`, `docs/experiments/`, `docs/POLYGON_*`) не трогать. `.env` не читать. Никаких
`git add`/`commit`/`reset`/`checkout` — дерево остаётся как есть, git трогает только оркестратор.
## 2. Что читать (карта, ≤5 позиций; порядок важен)
1. **`docs/research/28-contract-review.md` — ЦЕЛИКОМ, это носитель твоего задания.** Состав и порядок
батча — §5 · что резать — §5а · транспорт/сеть — §5б · решения владельца — §8 · форма модели
ошибок — §8 п.4 и §8а · инструкции лендинга — §8б. ⚠ Ревью-шапка приёмки в голове файла несёт
ПОПРАВКИ (важнейшие: К-10 закрывается «НЕ строить»; Б-0/Б-11а/Б-23 добавлены ПОСЛЕ адверсариального
судейства исходной сессии — их основания проверяй строже, одна подмена уже опрокинута эрратой
16.08-г) — читать тело через неё.
2. **D39.138 п.2 (живой `docs/architecture/05-decisions-log.md`, с хвоста)** — ратификация решений.
При расхождении формулировок research/28 и ноты побеждает НОТА.
3. **Канон 0.2.3 + компаньон** (`docs/architecture/14-api-contract/`) — целиком, до правок: ты обязан
знать, что ломаешь и почему оно было таким (у половины форм есть записанные обоснования — их
судьба решается, а не игнорируется).
4. Код трёх зон — по мере нужды, read-only. `file:line`-якоря отчёта research/28 — отправные точки,
**код первичен**: перед тем как записать в спеку факт о поведении сервера/клиента, открой место
и перепроверь (якоря могли уплыть).
5. `CLAUDE.md` (корень) — гардрейлы проекта; `docs/glossary.md` — жаргон.
## 3. Ратифицировано — делай РОВНО так (отступление = пинг владельцу, не тихая девиация)
Состав и порядок — **research/28 §5** (здесь не пересказывается — не дублировать носитель).
Несущие рамки из D39.138 п.2, которые обязаны выжить в любой твоей редакции:
- **Порядок исполнения не косметика:** Б-1 (модель ошибок) — ПЕРВОЙ: от словаря кодов зависят
формулировки Б-2/Б-3/Б-8/Б-14а/§8а.
- **Б-0:** конвейер уходит с провода. `Progress` → один счётчик до ближайшей остановки, знаменатель —
КУПЛЕННЫЙ объём (после подписи банка полоса заново); **счётчик ГЛАВЫ — той же сегментной логикой**
(«сделано в текущем сегменте / всего в сегменте»), иначе дерево глав читает ноль всю черновую волну —
исходная жалоба К-10, снятие фаз её само по себе не лечит; `finalizing` снять из словарей (устная
фраза владельца, не норма — §8 п.15); `verify_bank``stop_for_signing` без упоминания следующей
фазы; `TermOrigin` снять/переименовать (`ruby` — паро-специфика, настоящая утечка); ⚠ **`TermStatus`
ОСТАВИТЬ осью** (эррата 16.08-г: это продуктовый «главный фильтр работы» экрана подписи, шов клиента
его уже потребляет) — переименовать лишь значения, читающиеся движковыми (`auto`); `Unit` описать без
«edit unit» и «1.9 на главу»; из ВСЕХ описаний вычистить конвейерные слова — они компилируются в
JSDoc клиента.
- **Б-1 — вариант B (§8 п.4 + §8а):** машинный `code` (двухуровневый: стабильный корневой +
расширяемый вложенный) + `request_id` (значение на сервере уже есть); `title`/`detail`
developer-facing, клиент НЕ показывает; серверная локализованная фраза — отдельным полем ТОЛЬКО
для неперечислимых причин; `errors[]` с указателем поля для валидации. Два класса конкретности:
класс 1 (детерминированные — вход/счёт) — конкретика максимальная; класс 2 (модельные — прескрин /
отказ провайдера / фильтр) — ОДИН грубый код на весь класс, без вариации между попытками (К-9:
`rejected` + грубый код, 12-й статус НЕ заводить).
- **В-6:** `run-options` и 409 на старте прогона получают `blocked: {code, book_id}` — почему вторая
книга не стартует (D39.138 п.2з; в 0.2.3 поля НЕТ — заводишь ты). **К-13-остаток:** описание
`paused_reason` `:879` «null in every other state» противоречит ратифицированному «paused+null» —
поправить (D39.138 п.4).
- **Б-11а/§5б шаги 34 — В БАТЧ (заказ ПОВЕРХ §5: в его перечне Б-11а нет — дыра носителя, вписано
пост-ревью 16.08):** правило кадра «несёт применимую дельту ЛИБО счётчик + скоуп (id сущности +
версия), но не заставляет перечитывать коллекцию» — вместо нынешнего необязательного «сервер МОЖЕТ
склеивать»; форма дельта-чтения банка/замечаний `?after_version=` — контрактная (иначе «кадр банка
на главу = 372 МБ/прогон» встраивается в P7 и снимается второй ломкой; строка 186 маршрутизирует
семантику сюда).
- **`Idempotency-Key` — семантику решаешь ТЫ, не P7:** окно хранения, область ключа, ответ на повтор
с другими параметрами — записать в спеку; P7 только реализует.
- **Жанр — выкинуть** из `BookIntake` и `Book` (Б-23; остальные половины удаления — строка 184, не твои).
- **Экспорт остаётся** и получает состояние отказа (Б-4: `state` вместо булева `ready`, `failure_code`,
`expires_at`, эхо формата, правило доступа к ссылке — ПТ-34).
- **Б-19:** запрет клиентской служебной метки «Глава {n}» СНЯТЬ (ратифицировано, решение 09.08).
Не путать две вещи: `title_raw`/`kind` — ВЫБОР ТВОЙ (заложить формой сейчас ЛИБО явно передать
дизайн-паку 161 записью в компаньоне — аргументируй); **структурная ВЕРСИЯ — обязательна батчу**
(Б-7, §5 п.9: версия в ответах и `hello`, `410` на исчезнувшую главу, `If-None-Match`/304) — её в
161 не сдвигать.
- **Версия = 0.3.0**, обычный ломающий минор; право ломать в 0.x — весь бета-период (§8 п.17).
- **НЕ заводить в батч:** `POST /books/{id}/parts` (строка 185, дизайн — пак 161) · историю прогонов
(в МВП не нужна) · двухшаговую загрузку · ленту изменений структуры · поиск/фильтр · «грубую группу
статуса». В компаньон они записываются НАПРАВЛЕНИЯМИ: где строка бэклога существует — с её номером
(185), где нет — с носителем «research/28 §5 „не в батч"» (строк под них сознательно не заводили;
выдумывать номера нельзя).
- **Не финализировать формы без источника (§5а-оговорка):** словарь ступеней замечаний НЕ проектировать
(К-6: владелец — «решим потом»), поля `BankTerm` НЕ добавлять (D39.136 п.4б) — чтения замечаний и
банка держать минимально-достаточными (Note.id/адресация и снимок подписи — Б-9/Б-14а — входят).
- **Гейт на утечку конвейера** (тест по образцу языкового) — фронт-половина, тебе НЕ строить (носитель —
пинг фронту 16.08 в `frontend/docs/frontend-PROGRESS.md`, исполнение при разморозке); ты записываешь
в компаньон само правило «на проводе нет имён стадий/волн и движковых словарей» как ревью-вопрос
каждой правки.
- **Граница «ровно так / сам» внутри пунктов §5:** ЧТО делать — ратифицировано; КАК выразить формой —
твоё везде, где §5/§8/D39.138 не фиксируют форму явно. Зависимость исполнения: словарь кодов (Б-1)
определи ДО формулировок Б-2/Б-3/Б-8/Б-14а — порядок списка §5 (Б-0 нулевым) этому не противоречит.
## 4. Реши сам и аргументируй в отчёте
Точные имена полей и значений словаря кодов (класс 1 — из реальных причин `fail()` платформы, читай
код) · формы схем (пять конвертов списков на `allOf` — §5а «слить формально») · состав и глубина
резки §5а (мёртвые поля/кадры — с обоснованием на каждое) · как записать сеть — РАЗВОДИ по
наблюдаемости, чтобы не упереться в Б-16: условные чтения (`ETag`/`If-None-Match`/304/`Vary`) —
нормативная спека, клиент это видит и обязан уметь; «включить gzip на edge» — эксплуатационное
примечание, не норма (Б-16 выносит требования деплоя из контракта) · формулировки всех описаний ·
размер страницы
замечаний: замера масштаба нет (500 выбрано без числа — открытый вход строки 183), нового числа не
выдумывай — оставь с оговоркой в компаньоне. Совет-приор (опровергается
аргументом): для правил, которые OpenAPI не выражает (межполевые инварианты, условная обязательность),
образец уже есть в спеке — `BankDecision.dst` через `if/then` плюс прозу; помни улику К-11: генераторы
`if/then` игнорируют, значит правило обязано жить и словами для клиента.
## 5. Компаньон — ВМЕСТЕ со спекой (не после)
(а) Снять опровергнутые утверждения: ответ §5 «добавлена волна → фронт не правится» (опровергнут
исполнением, Б-0) · «канала банка нет» §3 против собственной строки 267 (Б-7а) · resume-абзац
(Б-7а п.4: лечение «новый прогон с бОльшим потолком» существует). (б) Завести таблицу
«чтение → источник → строка бэклога» и правило «предупреждение о недостроенном несёт номер строки»
(Б-21). (в) Обновить провенанс-классы ✓/◆/○ под 0.3.0. (г) Приложение А (карта «код → фраза»):
структуру перевести на словарь кодов Б-1, СЛОВА не заполнять — фразы пишет владелец (строка 148).
(д) Генезис-прозу из спеки (история ратификаций, апологии RFC — §5а называет места) переносить в
компаньон, не удалять.
## 6. Мандат самопроверки — исполнением, не заявлением
1. **Линт (форма проверена исполнением 16.08):** `cd frontend && npx spectral lint
../docs/architecture/14-api-contract/openapi.yaml --ruleset .spectral.yaml --fail-severity=warn`
— exit 0 (предупреждение валит так же, как ошибка). Читать/запускать фронт-тулинг можно,
писать в зону фронта — нет.
2. **Записка-план** (норма D39.121): каждый пункт §5 research/28 (включая однострочники и §5а)
И каждый подпункт §5(а)(д) ЭТОГО промта (компаньон — половина заказа) получает строку
«исполнено, где / отказ, почему» — сдача = все ID с диспозицией; это же — скелет твоего отчёта.
Комплектность против заказа — механически, не по памяти.
3. **Предметные оси** (право снять/добавить свою — с аргументом): (а) «второй клиент» — РЕАЛЬНО
прогони генератор по своей схеме (`cd frontend && npx openapi-typescript ../docs/architecture/14-api-contract/openapi.yaml -o /tmp/schema-probe.ts`
— read-only использование фронт-тулинга, вывод вне зон): не указывает ли схема нарушить
собственную прозу (класс PD-172: порядок свойств `BookIntake` указывал класть файл вторым);
«мысленная генерация» исполнением не считается; (б) анти-утечка — греп
финальной спеки по словарю конвейера (draft/edit/wave/stage/mined/ruby/finalizing и что найдёшь
сам); (в) каждое «оставить как есть» в спорном месте несёт записанный контраргумент (анти-инерция).
4. **Заявление = команда:** каждое числовое/категорическое утверждение отчёта — с командой, которой
получено; приёмка их пере-ранит.
5. **Адверсариальное селф-ревью — МЕХАНИЗМОМ, не стилем чтения (норма 6а: субагенты РАЗРЕШЕНЫ явно,
спавнь их).** После завершения правок запусти ≥2 независимых ревьюера-субагента, author≠reviewer —
они видят только артефакты, НЕ твой ход мысли: (а) **опровергатель полноты** — получает research/28
§5/§5а/§8а + D39.138 п.2 и финальный дифф спеки, мандат «найди пункты заказа, исполненные неверно
или неполно, и правки СВЕРХ заказа»; (б) **холодный потребитель** — получает ТОЛЬКО новую спеку
(без ревью, без компаньона, без диффа), мандат «ты пишешь клиента с нуля: назови всё непонятное,
противоречивое и места, где схема указывает нарушить собственную прозу». Проверяемый артефакт:
секция отчёта — таблица их находок, КАЖДАЯ с диспозицией (исправлено / отклонено-с-причиной);
ноль находок у обоих = повод не верить прогону, а не праздновать.
6. Несогласие с ратифицированным решением — СТОП по этому пункту и пинг через владельца с аргументом;
у тебя есть право сказать «этого делать не надо» — но не право молча сделать иначе.
## 7. Эхо-протокол старта
Первый деливерабл — ≤10 строк: «что я понял: скоуп / инварианты / чего НЕ делаю». Расхождение чинится
на минуте пять, не на приёмке.
## 8. Сдача
Отчёт `docs/archive/reports/CONTRACT_BATCH_0.3.0_REPORT.md`: записка-план §6.2 с диспозициями ·
таблица находок адверсариального селф-ревью §6.5 с диспозициями · спорные формы с вариантами и твоим
выбором · **obstacle reporting — что НЕ удалось/не сделано и почему (обязательная секция)** ·
дифф-сводка «было → стало» по операциям. Без саги. Дерево оставить
незакоммиченным. Вопросы и конфликты промта с кодом/доками — пинг оркестратору через владельца,
НЕ интерпретация.
---
## ДОФИКС-РАУНД (заказ приёмки D39.142, 16.08; аддендум — доезжает релеем владельца, подтверди эхом)
Батч ПРИНЯТ и заленден (панель: слепая сверка — потерь 0/искажений 0; аудит отчёта — 25+ клеймов сошлись). Дофикс — находки ХОЛОДНОГО ПОТРЕБИТЕЛЯ (линза, которой у твоего селф-ревью не было: только финальная спека + tsc-проба) и хвосты аудита. Зона и гейты прежние. Ратификации приёмки, которые НЕ двигать: прогонный поток снят · `Note.code` вместо `message` · `content_refused` остаётся · единый `page_size_default` принят. По каждому ФБ — диспозиция в дополнении к отчёту.
**ФБ-1 (HIGH).** Wire-форма SSE-кадра неоднозначна: `EventEnvelope{event,id,data}` как объект против `event:`/`id:` как SSE-фрейминг — два верных чтения (улика: A3 панели). Записать однозначно.
**ФБ-2 (HIGH).** Книга в покое без единого кадра истории: `hello` не имеет id последнего кадра → клиент без `Last-Event-ID` → «всегда новый поток» → hello→end→close→reconnect навечно (A4). Определить поведение.
**ФБ-3 (HIGH).** «`note` не теряется» не переживает reconnect: буфер не гарантирован, resync не шлётся (A5). Записать обязанность клиента: дельта-чтение `/notes?after_version=` после КАЖДОГО переподключения (механизм уже есть — назвать долг).
**ФБ-4 (HIGH).** `Revision` противоречит себе: «каждое книжное чтение несёт одно число» vs «рваное чтение = ревизия СТАРЕЙШЕЙ страницы» vs водяной знак «ревизия только что полученного конверта» (C1/A6); `BookDetail.revision` vs `book.revision` — равенство не заявлено (C2). Свести в одну модель; правило водяного знака при много-страничной дельте — явно.
**ФБ-5 (MED).** `EventEnd`/`EventResyncRequired` — пустые `allOf`-члены дают необитаемые типы (`Record<string,never>`, B1); дать им явные `properties` (хотя бы `{}` честной формой) и подсказку маппинга event→payload машинно-дружелюбнее (B2 — можно прозой-таблицей + непересекающимися формами).
**ФБ-6 (MED).** Спека приказывает предлагать «новый прогон» как лечение стопа по потолку, но resumable-статусы не перечислены, а `paused_reason:null` описан «нейтрально, continuable» (A1/A2). БЕЗ нового значения enum (ратификацию D39.132 п.2а не двигать): записать — «новый прогон с бОльшим потолком» легален для ЛЮБОГО paused; перечислить, что делает `resume` по каждому останавливающему статусу.
**ФБ-7 (MED).** Правило «ответ НЕ `problem+json`» (прокси 502, HTML, обрыв) — потерянный пункт заказа (Б-1 рек. п.4): клиенту нельзя показывать серверный текст и нечем взять код — записать нейтральный fallback (E1).
**ФБ-8 (MED, пачка одной строкой каждая).** merge-patch `title:null`→400 против RFC 7386 — объяснить в описании (C6) · `X-TM-Client` required против освобождения bearer — записать разводку в самом параметре (C8) · список «Refusals:» пометить неисчерпывающим (C5) · правило резолюции `Location` (A7) · тождество `Idempotency-Key` на multipart + путь ретрая 408-под-тем-же-ключом (A9) · `min_chapters` при `max=0` (A11) · приоритет пяти носителей «нет кредита» (A12) · «carried forward marked as unverified» — носителя на проводе нет: снять или дать (A13) · 409 у `createExport` объяснить (A14) · код для неизвестного `term_id` в decisions (A15).
**ФБ-9 (LOW).** `parser_unavailable` — имя компонента в enum, переименовать по эффекту (L1) · внутренние ссылки `research/28 §…`/«companion К-6» уезжают в исходники клиента — вычистить из описаний, оставить в компаньоне (L3).
**ФБ-10 (отчёт).** Пере-ран чисел ПОСЛЕ последней правки: строки файла (2315, не 2290) · `ErrorCode` 16, не 15 · генератор 2608 · «26 находок» → фактические 57/67 · «все девять» §5.3 → 11 строк · «8 из 20 не отвечает» → 12 из 20 · якорь `mining.go:201` → :81/:243 · «строка 21» → 18; скрипт мерки прозы/формы приложить в отчёт или снять вывод о доле; дописать строки записки-плана Б-23/К-10/В-6; ярлык §5.5 «исполнено иначе» → «отступление, аргумент»; README §6а — фраза «апологии перенесены» → «ужаты на месте».