diff --git a/docs/BACKEND_BANK_CLUSTER_FIXPACK_SESSION_PROMPT.md b/docs/BACKEND_BANK_CLUSTER_FIXPACK_SESSION_PROMPT.md index d8b64491..4aa1b2bc 100644 --- a/docs/BACKEND_BANK_CLUSTER_FIXPACK_SESSION_PROMPT.md +++ b/docs/BACKEND_BANK_CLUSTER_FIXPACK_SESSION_PROMPT.md @@ -1,6 +1,6 @@ # Промт бэкенд-сессии: ФИКС-ПАК БАНКА «КЛАСТЕРЫ + НАБЛЮДАЕМОСТЬ» (строка 128, + хвост 129) -**Выдан 04.08.2026, оркестратор №13, по санкции владельца 04.08 (зафиксирована D39.103 п.1; гейт строки 128 снят) и D39.102.** Ты — бэкенд-сессия. Зона записи: `backend/` (код+тесты+puml тем же коммитом-пакетом) + отчёт `docs/archive/reports/BANK_CLUSTER_FIXPACK_2026-08-XX.md` + пинг в `docs/PROGRESS.md` секция «Бэкенд». **НЕ коммитишь** — дерево готовишь, лендит оркестратор. ⚠ В дереве живёт ЧУЖОЕ: `platform/*` (модифицированный и новый, ждёт приёмки P0) — не трогать и не «прибирать». **Деньги: $0 — платных вызовов НЕТ вообще**; тесты и голден локально. Перекупка бэнк-батчей случится на следующем живом прогоне — в пак не входит, её цену только НАЗВАТЬ в отчёте. +**Выдан 04.08.2026, оркестратор №13, по санкции владельца 04.08 (зафиксирована D39.103 п.1; гейт строки 128 снят) и D39.102.** Ты — бэкенд-сессия. Зона записи: `backend/` (код+тесты+puml тем же коммитом-пакетом) + отчёт `docs/archive/reports/BANK_CLUSTER_FIXPACK_2026-08-XX.md` + пинг в `docs/PROGRESS.md` секция «Бэкенд». **НЕ коммитишь** — дерево готовишь, лендит оркестратор. ⚠ **Состояние дерева сверь `git status` В НАЧАЛЕ сессии — этот абзац устаревает быстрее промта.** На 08.08: платформа принята и залендена целиком (D39.109/D39.114), фронт S3 принят (D39.115), а ЖИВАЯ параллельная работа — полигон эксп-21: `eval/`, `docs/experiments/21-role-topology.md` и секция «Полигон» в `docs/PROGRESS.md`. Чужого не трогать и не «прибирать»: 08.08 такая правка стоила семи файлов (D39.113). **Деньги: $0 — платных вызовов НЕТ вообще**; тесты и голден локально. Перекупка бэнк-батчей случится на следующем живом прогоне — в пак не входит, её цену только НАЗВАТЬ в отчёте. **Первый деливерабл — эхо-блок ≤10 строк** (как понял скоуп · четыре работы + хвост · инварианты · что вне скоупа; подтверждения не жди). @@ -34,4 +34,4 @@ ## §4. Самопроверка и СТОП -Гардрейлы, задеваемые работами: **`backend/.env` НЕ читать** · **PUML не рендерить в svg/png** (владелец смотрит расширением). Мандат 12.07: ревью ИСПОЛНЕНИЕМ своего кода + явный бэкенд-ревью после кода. Вся батарея (`go build ./... && go vet ./... && go test ./...`) зелёная; archguard-тесты не трогать. Отчёт: что сделано по каждой работе с `file:line` · девиации от этого промта с причинами · фолд-предъявление §3 · чего НЕ сделал и почему · **план верификации эффекта на следующем ХОЛОДНОМ прогоне** (D39.103 п.1; что и как смотреть — назвать конкретно). Пинг в PROGRESS «Бэкенд» кратко. **СТОП — приёмка оркестратора** (адверсариальная, клеймы пере-проверяются исполнением). +Гардрейлы, задеваемые работами: **`backend/.env` НЕ читать** · **PUML не рендерить в svg/png** (владелец смотрит расширением). Мандат 12.07: ревью ИСПОЛНЕНИЕМ своего кода + явный бэкенд-ревью после кода. Вся батарея (`go build ./... && go vet ./... && go test ./...`) зелёная; archguard-тесты не трогать. Отчёт: что сделано по каждой работе с `file:line` · девиации от этого промта с причинами · фолд-предъявление §3 · чего НЕ сделал и почему · **план верификации эффекта на следующем ХОЛОДНОМ прогоне** (D39.103 п.1; что и как смотреть — назвать конкретно). Пинг в PROGRESS «Бэкенд» кратко. ⚠ **Протокол правки этого файла (куплен инцидентом D39.113):** ТОЛЬКО append в свою секцию «Бэкенд»; CURRENT-STATE и чужие секции не касаться; `git status` до и после. Если файл модифицирован чужой сессией — пинг в ОТЧЁТ, вливает оркестратор. **СТОП — приёмка оркестратора** (адверсариальная, клеймы пере-проверяются исполнением). diff --git a/docs/POLYGON_PACKAGE4_SESSION_PROMPT.md b/docs/POLYGON_PACKAGE4_SESSION_PROMPT.md index ce996241..ec7a946d 100644 --- a/docs/POLYGON_PACKAGE4_SESSION_PROMPT.md +++ b/docs/POLYGON_PACKAGE4_SESSION_PROMPT.md @@ -24,7 +24,12 @@ ## Задачи (по приоритету) -### 1. Сид-обогащение 蛊真人 — ГЕЙТИТ ЭТАП B (D24.4) +### 1. Сид-обогащение — ⚠ ИСПОЛНЕНО (D32), НЕ ИСПОЛНЯТЬ ЗАНОВО + +> Влито в `guzhenren-seed-v2.yaml`; императив ниже относится к МЁРТВОМУ `guzhenren-seed.yaml` v1 и +> оставлен как история. Правка v1 = работа впустую плюс смена content-hash памяти и лишний resnapshot. + +#### Историческое тело 蛊真人 — ГЕЙТИТ ЭТАП B (D24.4) - Пройти все 49 записей `guzhenren-seed.yaml`: дописать **мн.ч. (все падежи мн.ч., где термин счётный)** в `decl.forms` — этап A дал 18 ложных промахов класса inflection_gap (元石→«первокамней/первокамни/первокамнями», 凡人→«смертных/смертными», 蛊师→«гу-мастеров»). Именительный ед.ч. дублировать НЕ нужно (код с пакета №5 всегда проверяет базовый dst — D24.4). - Не менять dst/статусы/окна (白凝冰 gender=hidden — не трогать, D19.3). Изменение сида = memory content-hash (D8) → resnapshot: координируется оркестратором ВМЕСТЕ с лендингом бэкенд-пакета №5 — один resnapshot на всё. diff --git a/docs/README.md b/docs/README.md index 3b643ee4..5cce43bb 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,7 +2,7 @@ Проект: издательский художественный перевод крупных текстов (книги, ранобэ, вебновеллы; zh/ja/en→ru) мультиагентным пайплайном поверх LLM API. Go-бэкенд + веб-фронт ридер-IDE (Ф3) + платформа (SaaS control plane, `platform/`, D39.81). Цели и мерило — канон в [../CLAUDE.md](../CLAUDE.md); онбординг сессий — там же. Стартовый бриф владельца: [../START_PROMT.MD](../START_PROMT.MD) — **живой документ**, его V-идеи разобраны в реестр требований (ниже). -**Состояние проекта НЕ здесь.** Очередь, курс, бэклог — CURRENT-STATE в шапке [PROGRESS.md](PROGRESS.md); решения — [architecture/05-decisions-log.md](architecture/05-decisions-log.md) (при конфликте с любым доком побеждает он). Эта страница — только карта «что где лежит». +**Состояние проекта НЕ здесь** — кроме одной строки ниже, и это осознанное исключение: строка «активные промты» отвечает на вопрос «какой файл мой», без которого холодная сессия выбирает роль сама (нашёл слепой онбординг-замер 08.08). Всё остальное состояние — Очередь, курс, бэклог — CURRENT-STATE в шапке [PROGRESS.md](PROGRESS.md); решения — [architecture/05-decisions-log.md](architecture/05-decisions-log.md) (при конфликте с любым доком побеждает он). Эта страница — только карта «что где лежит». ## Карта @@ -16,7 +16,7 @@ - `research/` — фактура ресёрчей 01–25; у принятых — ревью-шапки, часть тел под ⚠ superseded: **читай баннер прежде содержимого**. Ключевые для навигации: 15 голос · 16 ридер-IDE · 17 внешняя критика · 18 рычаги качества · 19 нарезка · 20 банк-майнинг · 21 обзор транспорта · 22 доменные харнессы · 23 шов движок↔платформа (транспорт superseded D39.106) · 25 холодное ревью шва — форма D39.106, отвергнутые альтернативы, требования к эмиттеру (читать перед любым кодом стыка) · 24 арбитраж банка (ПРИНЯТ D39.102: консилиум закрыт классом, вход фикс-пака банка — §G). - [PROGRESS.md](PROGRESS.md) — журнал: CURRENT-STATE + **ЕДИНЫЙ БЭКЛОГ** (единственный трекер) + живой хвост хроники. НЕ источник решений. - `scripts/counts.py` — **производные числа доков считаются им, а не руками** (голова по трём носителям · счёт очереди и зон · вес открытых строк регистра платформы); `--check` даёт ненулевой код на расхождении. Его же зовёт зонный хук `scripts/githooks/pre-commit` при коммите, задевающем D-лог или PROGRESS — предупреждает, не блокирует. Заведено по D39.112 п.5б: голова отставала трижды у трёх разных оркестраторов. -- Активные хендофф-промты сессий (состав обновляется при каждом лендинге — норма D39.80): [ORCHESTRATOR_SESSION_PROMPT.md](ORCHESTRATOR_SESSION_PROMPT.md) (роль/нормы; состояния не дублирует) · [POLYGON_PACKAGE4_SESSION_PROMPT.md](POLYGON_PACKAGE4_SESSION_PROMPT.md) (полигон, отложен) · **платформа: [../platform/docs/PLATFORM_SESSION_PROMPT.md](../platform/docs/PLATFORM_SESSION_PROMPT.md) — ОТРАБОТАН (P0 ПРИНЯТ D39.107; P1+P2 ПРИНЯТЫ и залендены D39.109, регистр до PD-107); следующий промт платформы — по слову владельца (реконсилятор/тейлер/юниты, D39.107 п.3(3))** · фронт: `frontend/docs/S3_SESSION_PROMPT.md` (замок ОТКРЫТ — контракт ратифицирован D39.99; первый шаг — правки спеки: D39.100 + **новые В-трис/В-кватер от №15, D39.110** — управляемый потолок в главах и запрет проектировать кросс-origin, CORS в платформе нет). Зонные журналы фронта/платформы — `frontend-PROGRESS.md` / `platform-PROGRESS.md` в их зонах (решение владельца 04.08: прогресс зон только там). **Бэкенд: [BACKEND_BANK_CLUSTER_FIXPACK_SESSION_PROMPT.md](BACKEND_BANK_CLUSTER_FIXPACK_SESSION_PROMPT.md)** (фикс-пак банка, строка 128+129; санкция D39.103) · **Полигон: [POLYGON_ROLE_TOPOLOGY_SESSION_PROMPT.md](POLYGON_ROLE_TOPOLOGY_SESSION_PROMPT.md)** (эксп-21 «топология ролей»: скрин моделей → бейк-офф топологий на невиданном срезе; потолки предварительные, ЗАПУСК = слово владельца; D39.108). Очередь и состояние — только CURRENT-STATE. +- Активные хендофф-промты сессий (состав обновляется при каждом лендинге — норма D39.80): [ORCHESTRATOR_SESSION_PROMPT.md](ORCHESTRATOR_SESSION_PROMPT.md) (роль/нормы; состояния не дублирует) · [POLYGON_PACKAGE4_SESSION_PROMPT.md](POLYGON_PACKAGE4_SESSION_PROMPT.md) (полигон, отложен) · **платформа: ОТРАБОТАН ЦЕЛИКОМ** — четыре сессии (P0 D39.107 · P1+P2 D39.109 · фикс-пак P3 D39.114); текст в архиве, [`archive/prompts/PLATFORM_P0_SESSION_PROMPT_2026-08-04.md`](archive/prompts/PLATFORM_P0_SESSION_PROMPT_2026-08-04.md), копия с баннером ещё лежит в зоне. Следующий промт платформы — по слову владельца (реконсилятор/тейлер/юниты, D39.107 п.3(3)) · **фронт: S3 ОТРАБОТАН и ПРИНЯТ D39.115** (контракт 0.2.0 в каноне, копии байт-равны, слой данных построен); текст в архиве, [`archive/prompts/FRONTEND_S3_SESSION_PROMPT_2026-08-04.md`](archive/prompts/FRONTEND_S3_SESSION_PROMPT_2026-08-04.md). Промт S4 — по слову владельца. Зонные журналы фронта/платформы — `frontend-PROGRESS.md` / `platform-PROGRESS.md` в их зонах (решение владельца 04.08: прогресс зон только там). **Бэкенд: [BACKEND_BANK_CLUSTER_FIXPACK_SESSION_PROMPT.md](BACKEND_BANK_CLUSTER_FIXPACK_SESSION_PROMPT.md)** (фикс-пак банка, строка 128+129; санкция D39.103) · **Полигон: [POLYGON_ROLE_TOPOLOGY_SESSION_PROMPT.md](POLYGON_ROLE_TOPOLOGY_SESSION_PROMPT.md)** (эксп-21 «топология ролей» — **ЗАПУЩЕН и оплачен стадиями, сессия ЖИВАЯ**; приёмка у ПАРАЛЛЕЛЬНОГО оркестратора, не №15; D39.108, инцидент восстановления — D39.113). Очередь и состояние — только CURRENT-STATE. - Зоны фронта (чужие, читать при касании стыка; каждая ведёт СВОЙ зонный бэклог — единый бэклог их строк не принимает, D39.84): [../frontend/](../frontend/) — веб-интерфейс: промт фронт-сессий S0–S7 + [STACK_DECISIONS.md](../frontend/docs/STACK_DECISIONS.md) (пины версий точными числами и ловушки, сверены с вебом 02.08) + [BACKLOG.md](../frontend/docs/BACKLOG.md) · [../platform/](../platform/) — SaaS control plane: README + [BACKLOG.md](../platform/BACKLOG.md) (П-1..П-5) + `docs/` (промт P0 · зонный журнал `platform-PROGRESS.md`). - `archive/` — история ([правила архива](archive/README.md)): закрытые промты (`prompts/`) · отчёты с ревью-шапками (`reports/` — на них ссылаются приёмки) · исполненные арх-доки (`architecture/`) · слайсы хроники `PROGRESS-*.md`. Инструкции оттуда не исполнять. - Диаграммы: [../backend/docs/components.puml](../backend/docs/components.puml) · [../backend/docs/pipeline.puml](../backend/docs/pipeline.puml) — дом рядом с кодом (D39.80), правятся бэкендом одним коммитом с кодом; вручную НЕ рендерить (владелец смотрит PlantUML-расширением VS Code). diff --git a/docs/architecture/14-api-contract/README.md b/docs/architecture/14-api-contract/README.md index 8d46b408..425f4619 100644 --- a/docs/architecture/14-api-contract/README.md +++ b/docs/architecture/14-api-contract/README.md @@ -38,7 +38,7 @@ openapi.yaml РЯДОМ (байт-копия зонной frontend/docs/api-cont > каждое решение, чем оно обосновано, что осталось открытым. При расхождении по ФОРМЕ > побеждает YAML; при вопросе «почему так» — этот файл. > -> **Статус: черновик фронт-сессии S3 на ратификацию.** Дом ратифицированной копии — +> **Статус: РАТИФИЦИРОВАН — D39.99 (04.08), контракт 0.2.0 (D39.115, 08.08).** Дом канона — этот каталог; `frontend/docs/api-contract/openapi.yaml` — байт-зеркало. ⚠ Испр. оркестратором №15 08.08: файл называл себя черновиком на ратификацию четверо суток ПОСЛЕ ратификации — тот же класс, что шапка `info` спеки. > `docs/architecture/14-api-contract/`, зона оркестратора; перенос делает он, генерация типов > после ратификации идёт из перенесённой копии — контракт первичен, код вторичен. > diff --git a/docs/archive/prompts/FRONTEND_S3_SESSION_PROMPT_2026-08-04.md b/docs/archive/prompts/FRONTEND_S3_SESSION_PROMPT_2026-08-04.md new file mode 100644 index 00000000..4b9069c9 --- /dev/null +++ b/docs/archive/prompts/FRONTEND_S3_SESSION_PROMPT_2026-08-04.md @@ -0,0 +1,336 @@ +> ⚠⚠ **ПРОМТ ОТРАБОТАН — исторический, НЕ задание.** Исполнен двумя фронт-сессиями (04.08 и 08.08), +> **ПРИНЯТ и заленден D39.115** (`60595f6`): контракт **0.2.0** в каноне, канон и зонная копия +> байт-равны, блоки компаньона 2.14–2.16 внесены, слой данных построен. **Список «Правки спеки» +> ниже ИСПОЛНЕН целиком — не исполнять заново: спека уже 0.2.0, и повторная правка откатит +> ратифицированный контракт.** Живое состояние зоны — `frontend-PROGRESS.md`; хвосты — `BACKLOG.md` +> (Ф-29 · Ф-30 · Ф-31/К-13 · Ф-32); следующий промт зоны (S4) выдаёт оркестратор по слову владельца. +> Архивная копия — `docs/archive/prompts/FRONTEND_S3_SESSION_PROMPT_2026-08-04.md`. + +# Промт: фронт-сессия S3 — слой данных + +Ты — фронтенд-сессия TextMachine, четвёртая по счёту. Зона записи — **только `frontend/`**; +сессия не коммитит — лендит оркестратор (протокол — стоящий промт `FRONTEND_SESSION_PROMPT.md` +§«Зона и git», он в силе целиком). Пре-коммит хук стоит и самоустанавливается при `npm install`. + +> Промт написан сессией S2 по просьбе владельца — как передача с той точки, где S2 встала. +> Ратифицирует и правит его оркестратор; при расхождении с его хендофф-промтом побеждает тот. + +## Входное состояние (04.08, проверено исполнением, а не заявлено) + +- **Пройдено S0–S2:** план · инструменты и скриншот-цикл · `tokens.css` по замерам референса · + оболочка трёх панелей (`src/shell/`) · примитивы `src/ui/` на `react-aria-components` · + витрина `/showcase` и нагрузочный `/scale` (2284 раздела, 1200 терминов). +- `npm run check` — 5 гейтов (prettier · eslint тип-осведомлённый · stylelint · tsc · vitest, + **77 тестов**), `npm run check:full` — + сборка + три скриншота с гейтом доступности axe. + Всё зелёное на 04.08. +- **Данные всё ещё синхронная фикстура:** `src/api/` отдаёт объекты из `src/mock/` напрямую. + Это диспозиция Ф-15, а не недосмотр: асинхронность приезжает вместе с MSW, то есть в S3. +- **Гейты, которые ты застаёшь:** одно место для цвета и размера (TSX-половина в + `eslint.config.js`, CSS-половина в `stylelint.config.js`) · три шва — фикстуры видит только + `src/api/`, глобальный CSS только `src/main.tsx`, `react-aria-components` только `src/ui/` — + закрытые и для статического, и для динамического импорта · сеть запрещена вне `src/api/` + во всех транспортах (`fetch`/`EventSource`/`WebSocket`/`XMLHttpRequest`, включая + `window.*`) · тест общности: код языка не зашивается в разметку, стили не ветвятся по + `:lang(…)` · контракт-тест токенов и структурные тесты CSS-модулей. +- Правки S2 и дофикс по ревью ЗАЛЕНДЕНЫ (`02872b6`) — восстанавливать нечего, дерево фронта чистое. + ⚠ В дереве могут лежать незакоммиченные файлы ДРУГИХ зон (параллельные сессии — норма): не трогать + и не «прибирать». + +## Замок снят (оркестратор №14, 05.08) + +Контракт существует и ратифицирован (`docs/architecture/14-api-contract/`, D39.99), строка 95 +закрыта, вторая сторона контракта — платформа — уже написана и принята: её скелет живёт в +`platform/` и ратифицированные ответы платформы вошли в список правок спеки ниже. Раздел «Если +замок закрыт» оставлен как исторический — исполнять его НЕ надо. Один сохраняющийся запрет: +не начинать «пока на своих типах, потом поправим» — моки, снятые не с того контракта, разойдутся +с API, ровно ради чего строка 95 и заводилась. + +## Обязательное чтение до кода (порядок) + +1. `frontend/docs/FRONTEND_SESSION_PROMPT.md` — стоящий промт: сценарий §3, жёсткие ограничения + §4, «как работать» §7. **Его не редактировать.** ⚠ Раскладка §2 частично устарела — её + перевешивают решения владельца из журнала зоны. +2. `frontend/docs/frontend-PROGRESS.md` целиком: «Текущее состояние» · «Решения владельца по продукту» · + «Открытые вопросы» · хронику 04.08 (в ней — что S2 построила, где отошла от референса и что + поправило ревью оркестратора). +3. `frontend/docs/FRONTEND_PLAN.md` — §0.1 (карта канона: что читать перед чем), **§0.2 + (транспорт: с движком фронт не разговаривает никогда — это ратифицированный анти-паттерн, + D39.81/D39.85)**, §5.4 и §5.4.1 (формы обхода гейтов и названные границы), **§6 (что уже + известно про движок и как это меняет форму данных — читать до первой строки типов)**. +4. `frontend/docs/STACK_DECISIONS.md` — §2 пины (там уже названы `@tanstack/react-query` и `msw`), + §5 транспорт и правила стрима, §7 риск ре-ингеста. Библиотеки сам не выбирай и версии + по памяти не «обновляй»: твои знания об экосистеме устарели, сверка — live по npm. +5. `docs/research/23-engine-platform-seam.md` — `docs/README.md` требует читать его **перед любым + кодом стыка**; форма событий и правило ре-синка оттуда. +6. `frontend/docs/BACKLOG.md` — строки **Ф-14** (вход фронта в контракт), **Ф-15** (закрывается + этой сессией), Ф-19, Ф-21. +7. `references/*.png` и `.shots/*.png` — открой и посмотри до первой правки. + +## Правки спеки — ПЕРВЫЙ шаг S3 (список актуализирован оркестратором №15, 07.08: добавлены В-трис и В-кватер) + +Контракт ратифицирован. Спеку правишь ты: минорный бамп версии, регенерация типов, батарея, +компаньон-К-таблица получает статусы. **Ниже — ПОЛНЫЙ список; он вырос с 04.08**, потому что +платформа ответила на свои К-вопросы и владелец сменил модель лимитов. Порядок правок твой, +но ни одна не «на потом»: спека — нормативная поверхность, и на ней уже стоит код платформы. + +**А-нуль. Шапка `info` спеки уже исправлена оркестратором №15 (07.08) — НЕ возвращай её обратно.** +Три дня после ратификации файл называл себя «DRAFT of frontend session S3 — not a ratified +contract» и ссылался на компаньон по пути, которого рядом с каноном нет. Сейчас там сказана +правда: ратифицирован D39.99, канон в `docs/architecture/14-api-contract/`, зонная копия — +байт-зеркало, компаньон = `README.md` рядом с каноном. **Твоё в этом пункте одно:** строка +`version` всё ещё `0.1.0-draft` — бампни её первым же действием (минорный бамп, как и сказано +ниже), и байт-сверку копий из пункта Д делай уже с этой шапкой. + +**А. Решения владельца 04.08 (D39.100).** +1. **К-1:** десять статусов приняты — статусов больше не трогать. +2. **К-8:** `BookStatus` получает 11-е значение **`paused`** (резюмируемый стоп; в `failed` не + мапить — спека это уже запрещает). Оповещение «перевод остановлен: лимиты исчерпаны». +3. **К-5:** `eta_seconds` в прогресс-модель (движок отдаёт, `status.go:112`; поле опциональное). +4. **К-3:** метка главы — ИЗ ДАННЫХ книги; зашитых форм «Глава N» не существует, легальна книга + без номеров и глав вовсе. Проверь спеку И фикстуры на зашитую форму. + +**Б. Ратифицированные ответы платформы. Это уже НЕ вопросы — это форма, которую спека обязана +выразить.** + +> ⚠ Ссылки на `platform/docs/*` ниже и в разделе Г — **происхождение, а не задание.** Всё, что тебе +> нужно, приведено в этом промте целиком. В зону платформы ходить НЕ надо: там прямо сейчас живая +> сессия, её документы движутся, и промт, который зависит от чужого живого файла, ломается ровно в +> тот момент, когда сосед его правит. Если всё же полезешь — только читать, и знай, что читаешь +> черновик. +5. **К-4 (ревизия):** счётчик пер-КНИЖНЫЙ, одно и то же число несут все книго-скоупные чтения и + `id` кадра потока. Прозой в спеку: ревизия монотонна В ПРЕДЕЛАХ скоупа и между скоупами не + сравнивается · отбрасывание устаревшего чтения — обязанность клиента · докачка по + `Last-Event-ID` читает **`revision >= R`**, не `>` (одна транзакция = одна ревизия, но + НЕСКОЛЬКО кадров; строгое «больше» теряет кадры-братья) · после транзакции ПОЛНОЙ ЗАМЕНЫ + (банк пересобирается целиком, пере-чанковка заменяет главы) сервер обязан выдать + `resync_required`: дельта-чтение удаления выразить не может. +6. **К-7 (пагинация):** keyset-курсор на КАЖДОМ списочном ответе, `?limit=&cursor=`, + `next_cursor: string|null` присутствует ВСЕГДА (добавить позже — значит молча отрезать хвост + у клиента, который поля не читает). Дефолты: главы 5000 · банк 1000 · замечания 500. + ⚠ Курсор привязан к СТРУКТУРНОЙ эпохе (поколение манифеста / `chunker_version`), **НЕ к + ревизии книги**: ревизия бампается на каждой материализации, и привязка к ней даёт вечный + рестарт пагинации во время прогона на книге в 5000 глав. Отклонение протухшего курсора — + обязанность СЕРВЕРА (MUST), клиент её исполнить не может: курсор непрозрачен. +7. **К-12 (экспорт):** опрос, а не пуш. `202` + `Location`; статус-чтение отдаёт `ready:false` + с заголовком **`Retry-After`**, объявленным ЯВНО как заголовок этого 200-ответа (RFC 9110 + определяет его для 503 и 3xx — на 200 общая семантика не действует, поэтому объявляем сами). +8. **CSRF:** браузерный клиент обязан слать заголовок **`X-TM-Client`** на небезопасных запросах + cookie-пути. Место — описание `sessionCookie`. Несущим является ПРИСУТСТВИЕ заголовка, + значение любое: не выдумывай токенную семантику. +9. **`Run.paused_reason`** — машинная причина паузы либо `null`; фразу рисует клиент, API несёт + состояние. **Значение ровно одно и оно уже занято платформой: `credit_exhausted`.** (В редакции + этого промта от 05.08 стояло `limits_exhausted` — ошибка оркестратора, значение должно совпадать + с тем, что пишет платформа, иначе клиент не опознает причину.) + +**В. Решение владельца 05.08 — модель лимитов СМЕНИЛАСЬ.** Не подписка с окнами, а **БАЛАНС +кредитов** («покупка токенов как у OpenRouter»). Следствия для спеки: +10. Окон и `resets_at` НЕТ. Экран показывает ОСТАТОК, а не «сбросится через». Денежные СУММЫ + по-прежнему на провод не идут (D39.84) — процент остатка, не доллары. +11. Прежняя инструкция этого промта «API лимитов проектирует платформа, в спеку не выдумывать» + ОТМЕНЕНА: форма ответила (`GET /v0/usage`), и её надо выразить — но БЕЗ полей окон. Форма + приведена ЗДЕСЬ целиком, ходить за ней в чужую зону не нужно и не надо (промт, зависящий от + живого документа соседней зоны, ломается ровно тогда, когда сосед его правит): + + ```yaml + Usage: + required: [state, remaining_percent] + properties: + state: { enum: [ok, low, exhausted] } # low — порог показа предупреждения + remaining_percent: { type: integer, minimum: 0, maximum: 100 } + paused_reason: { enum: [credit_exhausted], nullable: true } + ``` + + Процент считается от суммы грантов аккаунта, не от «лимита периода»: периодов больше нет. + `Run.paused_reason` несёт то же значение на прогоне. Сумм нет ни в каком виде (D39.84). + (В редакции 05.08 этот пункт слал за схемой в `PLATFORM_DIRECTION.md` §2 — там её нет, там + денежная модель; ошибка оркестратора.) + +**В-бис. Поверхность входа — появилась в P1, в спеке её нет** (добавлено оркестратором 05.08 после +приёмки платформы P1; в редакции этого промта от 05.08 утра этого пункта не было, потому что кода +входа ещё не существовало). + +Платформа построила OIDC-вход. Четыре ручки живут ВНЕ версионного префикса, как `/healthz`, потому +что это механика сессии, а не контрактная поверхность: + +| Ручка | Метод | Что делает | +|---|---|---| +| `/auth/login` | GET | начинает вход, редиректит к провайдеру; принимает `?return_to=<путь на этом сайте>` | +| `/auth/callback` | GET | завершает вход, ставит сессионную куку, редиректит на `return_to` либо на дефолт | +| `/auth/logout` | POST | завершает ЭТУ сессию | +| `/auth/logout-all` | POST | завершает ВСЕ сессии пользователя («выйти везде») | + +15-бис. **Описать их в КОМПАНЬОНЕ, в `openapi.yaml` не тащить** — решение оркестратора как +владельца контракта. Клиенту нужно знать три вещи: куда вести на вход, что `return_to` принимает +только путь этого сайта (сервер молча заменит чужой на дефолт — открытый редирект закрыт), и что +обе `POST`-ручки лежат на cookie-пути, то есть требуют `X-TM-Client` из пункта 8. +Отказ входа — `problem+json`, как везде; различать причины отказа клиент не может и не должен. + +**Г. Ограничения скорости, которые спека обязана удержать** (замер и разбор — +`platform/docs/PLATFORM_DIRECTION.md` §4; для тебя это правила, а не предложения): +12. **Юниты читаются только пер-главно.** Пер-книжной ручки юнитов не заводить никогда — + на этом стоит вся память клиента (рабочий набор 27 КБ против ~62 МБ). +13. **Экспорт — артефакт по ссылке;** сборка текста книги на клиенте запрещена явно. +14. **Сервер ВПРАВЕ склеивать события прогресса**, клиент обязан терпеть скачки счётчиков — + записать в описания событий (иначе прогон на 9500 юнитов = неограниченный источник рендера). +15. **Заголовок главы ограничен по длине на сервере** — единственная неограниченная строка в + списке из 5000 строк. + +**В-трис. Управляемый потолок прогона — РЕШЕНИЕ ВЛАДЕЛЬЦА 07.08, поверхности в спеке нет** +(добавлено оркестратором №15 по приёмке платформы P2, D39.109/D39.110; в редакции 05.08 этого +пункта не было — решения не существовало). + +Проблема, которую это решает: перевод книги стоит денег, и человек должен уметь сказать «не +больше вот столько» ДО старта, а не узнавать пост-фактум. Сегодня потолок живёт только в конфиге +книги на стороне движка, и управлять им нельзя вообще. + +Форма, ратифицированная владельцем: **шкала в интерфейсе от минимума до максимума**, ноль выбрать +НЕЛЬЗЯ (подсвечивается серым — прогон с нулевым потолком не начнётся), виджет выбираешь сам +(ползунок — предложение владельца, не мандат). Три вещи в этой форме — «делай РОВНО так», потому +что каждая куплена проверкой: + +16. **Единица шкалы — ГЛАВЫ, а не доллары.** Не «поставить $3», а «перевести до N глав». Причина + жёсткая: D39.84 запрещает денежные суммы на пользовательском проводе и экране, и П-5 показывает + процент ровно поэтому. Доллары на этой шкале = амендмент D39.84, а он не выдан. Побочная + выгода: минимум шкалы объясняет себя сам — одна глава. +17. **Максимум шкалы = ДОСТУПНЫЙ остаток.** ⚠ **Первая редакция этого пункта говорила «баланс МИНУС открытые холды» — ошибка оркестратора, вычитание дважды; исправлено 08.08 по находке самой S3 (D39.115).** Холд — дебет в момент взятия, поэтому баланс уже без него. + Платформа берёт холд на сумму потолка ДО спавна прогона, поэтому шкала, упёртая в полный + баланс, запирает всё на одну книгу и вторую начать нельзя. Два числа платформа уже различает. +18. **Это потолок ПРОГОНА, не книги.** Он едет со стартом прогона и не является свойством книги; + в спеке ему место рядом с созданием прогона, а не в модели книги. + +⚠ Чего в спеке НЕ выражать: пересчёт «глав → деньги». Он живёт на платформе (по оценке движка) и +наружу не выходит ни в каком виде. Поверхность отдаёт границы шкалы и выбранное значение в главах. + +**В-кватер. ФРОНТ ЖИВЁТ НА ТОМ ЖЕ ORIGIN, что платформа — сегодня это не выбор, а факт** +(замер приёмки №15 на живом бинаре, строка PD-96 регистра платформы). + +CORS-слоя в платформе нет вовсе: preflight `OPTIONS` с чужим `Origin` получает 401 от гарда +сессии, заголовков `Access-Control-*` нет ни на одном ответе. Значит браузерный клиент с другого +origin неработоспособен как класс, а не «требует настройки». Для тебя два следствия: в деве ходи +через прокси dev-сервера на тот же origin (не напрямую на порт платформы), и **не проектируй ничего +вокруг кросс-origin запросов** — если продукт когда-нибудь потребует отдельный домен фронта, это +отдельная работа платформы, и она не сделана. Заголовок `X-TM-Client` (пункт 8) при этом обязателен +и на same-origin: он не про CORS. + +**Д. После правок:** байт-сверка зонной спеки с ратифицированной копией +(`docs/architecture/14-api-contract/openapi.yaml`); расхождение отдай оркестратору на +пере-ратификацию диффом — сам канон не правь. + +## Скоуп S3 — слой данных, и ни шагом дальше + +1. **`src/api/` становится асинхронным**: MSW как сетевой мок + серверное состояние на пинах + из STACK_DECISIONS §2 (версии сверить live на дату сессии; `.npmrc` держит `save-exact`). + Каждый новый пин — строкой в таблицу `FRONTEND_PLAN.md` с датой релиза и «зачем нам». +2. **Фикстуры всех состояний, а не одного счастливого:** ожидание · ошибка · пусто · + частично · длинный хвост · потеря соединения на стриме. Правило S1/S2, которое здесь + действует сильнее всего: **фикстура по умолчанию — трудный случай.** Наивный счётчик глав + должен на ней давать ноль (идёт черновая волна), иначе скриншот-цикл смотрит на удобное. +3. **Живой прогресс — `EventSource` за швом `src/api/`** (STACK_DECISIONS §5; гейт сети уже + запрещает его где-либо ещё). Докачка по `Last-Event-ID`/ревизии — часть контракта, не выдумка. +4. **Ф-15 закрывается здесь:** ветки ожидания/ошибки/пустоты появляются вместе с MSW, а не + после первого продуктового экрана. +5. **Типы `src/api/types.ts` приводятся к контракту.** Что в них сегодня заведомо временное: + булев `signed` вместо трёхзначного `auto|draft|approved` · ключ строки банка, собранный + из (`src`, `dst`, `type`), — у движка термин уникален по (`src`, `sense`, `since_ch`, + `until_ch`) · отсутствие ревизии для докачки. Всё это перечислено строкой Ф-14. + **Закрытые юнионы получают явную ветку неизвестного значения** (строка Ф-22) — сегодня её нет + ни у одного, и строгость тайпчека здесь НЕ страхует: `runStates[book.state]` + (`showcase/Library.tsx:103`) — обращение к `Record` по КОНЕЧНОМУ юниону, а + `noUncheckedIndexedAccess` добавляет `undefined` только индексным сигнатурам (проверено `tsc` + на пробе: обращение по юниону компилируется молча, ругается только `Record`). + Значит состояние прогона из будущего контракта даёт `undefined.tone` — падение дерева + библиотеки, а не пустую метку; `noteTone` тем же классом тихо уводит незнакомую ступень + замечания в СПОКОЙНУЮ ветку. **Место ветки — шов `src/api/`, где значение входит**, а не + каждый компонент: перевод «вердикт → вид» уже расползался по экранам, и контрольный вопрос + владельца требует, чтобы новое значение правило один файл. +6. **Поля не выдумывать.** Нет в контракте — это вопрос владельцу/оркестратору в + «Открытые вопросы» журнала зоны, а не догадка в типе. Дефект «фикстура выдумала поле» + в этой зоне случался дважды и оба раза стоил экрана. + +**Не в скоупе:** экраны S4–S7 · редактор текста · светлая тема · мобильная раскладка · +React Compiler (Ф-2) · Tauri (Ф-5). + +## Если замок закрыт + +Контингенция на случай, если проверка замка даст «закрыт» (на вечер 04.08 замок ОТКРЫТ); тогда правильный ход — не ждать молча и не строить экраны +на синхронных моках (порядок этапов Ф-1 стоит именно на слое данных). + +- **Доведи Ф-14 до артефакта, который можно отдать автору контракта:** не список намерений, + а перечень с обоснованием на каждый пункт — язык кодами · состояние прогона отдельно от + выполнения главы · прогресс пофазно по ЮНИТАМ · ревизия/`Last-Event-ID` · трёхзначный статус + подписи · поля банка (`type`/`sense`/`since_ch`) и ключ строки · продуктовый словарь вердиктов + (ПТ-33; §4.1 запрещает протечку внутренностей конвейера на экран). Половина уже написана + в строке Ф-14 и в §6 плана — собери, а не сочиняй заново. +- Отдай его оркестратору пингом в `frontend/docs/frontend-PROGRESS.md` и **остановись**: + заводить контракт своим решением фронт не может (шапка `BACKLOG.md`). + ⚠ **Испр. сессией S3 04.08 по слову владельца:** здесь стояло «пингом в `docs/PROGRESS.md`» — + это чужая зона, и шапка журнала фронта фиксирует решение владельца 02.08 «в `docs/PROGRESS.md` + оркестратора не пишут». Канал передачи — журнал своей зоны; оркестратор пишет туда же. +- Ф-16, Ф-17, Ф-18, Ф-20 — **не трогать**: у каждой в бэклоге стоит свой триггер, и ни один + из них не наступил. + +## Ловушки, купленные S2 — не переоткрывать + +- **`react-aria-components`:** `Tab` не принимает клавиатурных обработчиков (обработчик живёт + на ряду вкладок) · у роли `tab` дети презентационные, поэтому крестик закрытия — не кнопка + (axe роняет `nested-interactive`), закрытие с клавиатуры — `Delete`, объявить его нечем (Ф-17) · + **невыбранная `TabPanel` не рендерится вовсе** (`dist/private/Tabs.mjs:276`), отсюда потеря + прокрутки при переключении вкладки (Ф-19, замерено дважды) · `Tree` — это `treegrid`/`row`, + а не `treeitem`; раскрытие — `