# Промт: фронт-сессия S4 — библиотека, загрузка, разбор, прогресс (+ спек-правка 0.2.3) > Выдан оркестратором №16 14.08.2026 по D39.130 («гейт S4 пал»). Запуск — по слову владельца. ## 0. Какую проблему решаем и что даст твой результат Продукт — веб-сервис художественного перевода книг: пользователь загружает книгу, запускает перевод, подписывает словарь терминов, читает результат. Фронт строится этапами S0–S7; пройдено всё до S3.7 включительно: оболочка трёх панелей по референсу Fleet, слой данных на контракте OpenAPI (MSW как сетевой мок), i18n-каталог, гейты. Чего до сих пор НЕ существует — **пути пользователя от «у меня есть файл» до «книга переводится»**: форма добавления книги есть как вид (модал S3.5 по `antigravity_add_folder.png`), но никуда не отправляет; статусы `uploading`/`parsing`/`rejected` в контракте есть, а экраном не прожиты; запустить прогон с экрана нельзя. До сих пор это было честно: серверной ручки загрузки не существовало. 14.08 платформа P5 принята (D39.130) — `POST /books` построен и жив, и вместе с его приёмкой владелец контракта ратифицировал пакет правок спеки (**0.2.3**), которые вносишь ты. Твой результат = пользовательский путь загрузки и запуска работает на форме контракта 0.2.3, и следующая сессия (S5, подпись банка) строится на книге, которую в интерфейсе можно завести, а не только замокать. Ты — девятая фронт-сессия. Промт — твой ЕДИНСТВЕННЫЙ контекст: ты не видишь чужих переписок; всё несущее — здесь или в названных доках. Дом фронта остаётся миром моков (MSW по контракту); живой стенд платформы — только опциональная проба, §10. ## 1. Онбординг (порядок чтения, до кода) 1. `CLAUDE.md` (корень) — гардрейлы проекта; из них жёсткие для тебя: зона записи ТОЛЬКО `frontend/`, ты НЕ коммитишь, `.env` не читать, чужие незакоммиченные файлы не трогать. 2. `frontend/docs/FRONTEND_SESSION_PROMPT.md` — живой носитель норм зоны: §«Зона и git», §3 сценарий (тебе — §3.1–3.4), §4 жёсткие ограничения, §5.1 поддерживаемость, §7 «как работать». Статусные абзацы там частично исторические — статус этапов только в `frontend-PROGRESS.md`. 3. `frontend/docs/frontend-PROGRESS.md` — шапка «Текущее состояние» + раздел «Решения владельца по продукту» (перевешивает всё в старых промтах) + записи S3.5–S3.7 и приёмок. 4. `frontend/docs/BACKLOG.md` (Ф-строки) и `frontend/docs/STACK_DECISIONS.md` (пины — не двигать). 5. Контракт: зонная копия `frontend/docs/api-contract/openapi.yaml` (**0.2.2**, байт-зеркало канона `docs/architecture/14-api-contract/openapi.yaml`) + компаньон-README рядом с каноном (провенанс, К-вопросы, §2.15 — потолок прогона). 6. Референсы `frontend/references/*.png` — открой глазами, если трогаешь вид. **Эхо-протокол:** первый деливерабл — ≤10 строк «что я понял: скоуп / инварианты / не-делать» ДО работы. Расхождение чинится на минуте пять, не на приёмке. ## 2. Задача 1 — спек-правка 0.2.3 (делай РОВНО так; ратифицировано D39.130 п.2в + ратификация ниже) Правишь ЗОННУЮ копию `frontend/docs/api-contract/openapi.yaml`, бампаешь `info.version` до **0.2.3**, перегенерируешь типы (`npm run contract`), spectral зелёный. Канон правит оркестратор диффом при лендинге — байт-сверку не выравнивай сам, расхождение с каноном на время сессии легально (прецедент Ф-47/0.2.2). Пять правок: - **PD-172:** у `createBook` записать проводное правило — часть `file` идёт **последней** в multipart-форме; поля после файла = 400. Причина (одной строкой в описание): платформа читает форму потоково и обязана увидеть языки до тела файла. - **PD-173:** у отклонённой книги появляется **машинная причина** — поле с закрытым enum по словарю платформы (`source_unreadable` · `not_configured` · `parser_unavailable`; её колонка `books.reject_reason`, миграция 00013 — сверь имена значений по `platform/` read-only, код первичен). **Продуктовые фразы различения пишешь ТЫ** (слово владельца 14.08: «пусть сам придумает, только над хорошими вариантами подумает»). Рамки: фразы должны честно ложиться на РЕАЛЬНЫЙ флоу отказов (движок отдаёт платформе классы отказа, платформа сводит их в этот enum — прочитай маппинг read-only, чтобы фраза не врала о причине), при этом НЕ раскрывать внутреннее устройство (ПТ-33: ни стадий, ни моделей, ни слов вроде «манифест»/«парсер движка»; та же дисциплина, что у `Problem.title`) и не звучать тревожно (§3.8). Разное следующее действие — разные фразы: «файл не тот» → проверить файл; «сервис недоступен» → повторить позже. В UI — через словарь с веткой неизвестного, как все enum; свои фразы вынеси в отчёте отдельным списком на утверждение владельцем. - **PD-174:** назвать классы ответов, которые провод уже даёт, а спека молчит: 404 на `POST /books` у инстанса без интейка; 503 у `resume` на деплое без маркер-команды/шаблона потолка (0.2.1 ратифицировала 503 только для СТАРТА). - **PD-180:** описание `createBook` честное: **201 несёт `parsing`**, не «responds immediately … enters uploading» (`uploading` наблюдаем только параллельным чтением библиотеки); плюс перечень отказов интейка: 400 (>16 частей формы; текстовое поле >1 КиБ), 413 (потолок тела — порог принадлежит деплою, числа в спеку не зашивать), **408** (тело не успело за дедлайн маршрута — медленный клиент, лечение повтором). - **`title` в `BookIntake`** — необязательное поле: пустое/отсутствующее = «название даст разбор» (сегодня платформа берёт имя загруженного файла), заполненное = задано вручную и разбор его не перепишет. **Ратифицировано оркестратором 14.08** как исполнение замечания 12 владельца (S3.5: «автор вводит название руками ЛИБО скипает — источники различать»; форма это уже разводит, а отправить рукописное название до сих пор некуда — черновик S3.5 висел без ратификации). Владелец промт ревьюит — отмена этого пункта одной репликой; дошла отмена аддендумом → эхо-подтверди и отрази в отчёте. ## 3. Задача 2 — загрузка книги (форма → `createBook`) Половина Ф-26. Модал «Добавить книгу» отправляет форму через слой `src/api/` (типы `createBook` уже сгенерены), MSW-хендлер — по форме 0.2.3, включая порядок частей (file последним) и ветки отказов. Экранный путь по §3.2–3.3 сценария: - **Прогресс отправки файла** видимый (книги бывают десятки МиБ). `fetch` прогресса отправки не даёт — механизм выбери сам (XHR либо иное) и аргументируй в отчёте; слой данных остаётся одним входом, гейт транспорта (`src/api/**` only) в силе. - После 201 книга в библиотеке в `parsing` — **разбор это отдельный видимый шаг**, не часть перевода. ⚠ Числового прогресса разбора у контракта НЕТ — процент не выдумывать, честное состояние «разбирается»; по завершении главы появляются в дереве, статус `not_started`. - **Отказ (`rejected`) — с причиной** по PD-173 и советом, различимым по классу (файл не тот ≠ сервис недоступен), фразы — как в задаче 1. Отказные ветки (400/408/413/404) — честные состояния формы, не алерты; тон — §3.8 («если экран выглядит тревожным — он неправильный»). - Подтверждение успешной загрузки видимое: размер/объём/язык (§3.2) — из данных контракта (`character_count`, `chapter_count`, языки), не выдумывая полей. ## 4. Задача 3 — запуск прогона с ручкой потолка (остаток строки 126 единого бэклога) Форма запуска перевода. Ратифицировано (D39.110/115, компаньон §2.15 — не переоткрывать): - Перед показом формы читается `GET /books/{id}/run-options`; шкала потолка строится из `CeilingBounds` **в ГЛАВАХ** — никаких долларов, сумм и оценок стоимости на экране (§4.8 в силе; пересчёт «главы→деньги» — целиком платформа). - `ceiling_chapters` обязателен, **ноль выбрать нельзя**; предустановка шкалы = `default_chapters` от платформы (клиент своё значение не выбирает — это продуктовая политика); `max_chapters: 0` = старт недоступен, честное исчерпанное состояние вместо шкалы. - Bounds приходят готовыми и уже подрезанными — клиент **не клампит второй раз** и не выводит свои; между чтением и стартом они могут уехать — **409 на старте** обрабатывается пере-чтением run-options и честной фразой, не ретраем втихую. - Галочка «остановиться на подписи банка» (`verify_bank`) — параметр ЭТОГО запуска, не глобальная настройка (решение владельца 02.08, §4 п.11 промта зоны). - **`paused` — прожитое состояние прогресса** (ПТ-35: стоп по потолку = статус `paused` + оповещение). Фраза «остановлена: лимиты» зарезервирована за владельцем (В-3/В-6) — берёшь существующую из каталога, не переписываешь; механизм оповещения (статус-полоса/бейдж уже несут состояние — нужен ли отдельный тост) реши сам и аргументируй. После потолочного стопа `resume` сам по себе прогон не двигает — resume как «продолжить после потолка» не предлагать (описание `resume` в спеке); различение «свой потолок vs нет кредита» — К-13, на владельце, не решай. Страница лимитов `GET /usage` остаётся в настройках = S7 (Ф-27) — эту диспозицию не двигай. - ⚠ **На ЖИВОЙ платформе потолочный стоп сегодня приезжает `failed`** — потребительская половина шва (П-15 зоны платформы) ещё не построена, PD-113 открыт. В мире моков строй ПО КОНТРАКТУ (`paused`, `EventCeiling`); от живого стенда правильного поведения не жди и не подгоняй под него ни код, ни тесты. Прогресс во время прогона — по построенному `useRunStream`: пер-главные индикаторы в дереве и общий прогресс в статус-полосе уже живут на фикстурах (одна доля без названий фаз, ETA из `eta_seconds` — ратифицировано); доведи их до пути «книга, заведённая формой, переводится» в мире моков. Внутренности конвейера не раскрывать (§4.1). ## 5. Задача 4 — библиотека на настоящем масштабе - Хвост Ф-12: дерево глав ПЛОСКОЕ — на 2284 разделах нужна группировка (по сотням или иная — реши сам по референсу и замеру на `/scale`, аргументируй). - Все статусы `BookStatus` прожиты в дереве и карточке книги — включая `uploading` (виден параллельным чтением), `parsing`, `rejected` с причиной. Метки состояния — из словаря с веткой неизвестного; слова, зарезервированные за владельцем (В-3/В-8), НЕ трогать и не укорачивать. - Ф-42 (потолок keep-alive вкладок) — по замеру: реши сам, чинить или отложить с записью. ## 6. Задача 5 — находки приёмки S3.7 (все получают диспозицию) Ревью приёмки: 12 подтверждённых (1 high) + 16 минорных. Из подтверждённых **9 несущих — список ниже**; остальные 3 — поправки к записи S3.7 (цена бандла, дрейф ширин `hidden`, счёт «106 из 119»), их носители — запись оркестратора 14.08 в журнале и задача 7. Каждой — диспозиция в записке-плане (починено с тестом / не воспроизводится с замером / отложено со строкой): 1. **(high) Дубль подстановки строк:** запись S3.7 ложно клеймила «заполнение вынесено в `src/i18n/fill.ts`, его импортируют и приложение, и сцены» — `scenes.mjs` держит собственный инлайн-филлер `say()` с ДРУГОЙ семантикой пропуска, добавленный самой S3.7. Сведи к одному носителю. 2. Отметка «перечитывание в пути» ставится без старта чтения и глушит следующие кадры ключа (`useRunStream.ts:146` на момент приёмки). 3. `onResync` не чистит `asked` — отметки прежней эпохи съедают кадр в окне ресинка (`:42`). 4. Клейм «resync не рвёт живой поток» — принять только по живому инструментированному прогону с задержкой ответа (статика `resetQueries` говорит обратное). 5. Сцена `hidden`: прекондиция «ушли до прихода банка» не ассертится (гонка с синхронным моком), сторож дифференциальный — симметричная регрессия замера пройдёт; и «таблица вообще нарисована» не проверяется (два пустых замера равны). 6. Дырка ESLint-гейта строк: вычисленный литерал (`?? 'Word'`, тернарник) в читаемом атрибуте и литерал в expression-child проходят — живой экземпляр `Showcase.tsx:134`. 7. Perf-оседание может проходить вакуумно: заходы 2–5 ждут 300 мс против конвенции 700. 8. Zoom-ассерт «в ряд» не запрещает стопку (сравнивает left с left, не с right). 9. Кадр `status` не перечитывает список глав — по собственной посылке Ф-49 его счётчики на границе стадии тоже протухают. Минорные (актуальный остаток свода; часть уже закрыта попутно — сверь и диспозиционируй коротко): свип языка `catalogue.test.ts` не метёт `package.json` и безрасширенный `scripts/githooks/pre-commit` · гейт вызовов каталога держится на имени локальной переменной `text` · шапка `ru.ts` ссылается на несуществующий `src/i18n.test.ts` · perf: удлинение запроса с 3 до 5 символов само занижает мс/клавишу · защёлка флага съёмки — эвристика окна 150 мс (знать, не чинить без замера). `file:line` — ориентиры на момент приёмки, код первичен. Несогласие с находкой = диспозиция с замером, не молчание (образец: арбитраж 8.1, где права оказалась сессия). ## 7. Задача 6 — гигиена зонных доков и арбитраж двух чисел Стейлы (аудит-свип 14.08), чинить по факту кода: - `FRONTEND_PLAN.md:42-43` — «платформа = ноль строк кода» устарело (P5 принята, D39.130); `:26-30` — таблица §0.1 подаёт строки 95/99–103 как «чего ещё нет» (95 ратифицирована D39.99, 99/100/103 построены D39.122/131) и шлёт читать `API_CONTRACT_INPUT.md` как живой вход (он под баннером «исполнено»); `:207-208` — ссылка на удалённый `src/api/types.ts`. - `STACK_DECISIONS.md:179` — тулчейн платформы «≥1.26.5» → ратифицирован **1.26.6** (D39.130); `:144` — состав `npm run check` отстал (4 шага против нынешних 7). - `FRONTEND_SESSION_PROMPT.md:62` — «скелет P0 ждёт приёмки» → P5 принята и залендена. - `frontend/README.md:63-66` — зонная копия спеки названа «черновик на ратификацию» — она давно байт-зеркало ратифицированного канона (D39.99/115). Арбитраж чисел ЗАМЕРОМ (два носителя врозь, оба претендуют на факт): цена бандла i18n — запись S3.7 говорит «724130 (+7999)», Ф-35 говорит «723102 (+6971)»; ключей каталога — запись «147», Ф-35 и живой `ru.ts` — «157» (верно 157). Прогони сборку и счёт ключей на текущем дереве, живые носители (BACKLOG/план) приведи к замеру; записи хроники НЕ правятся — расхождение назови попуткой в своей записи. ## 8. Задача 7 — завести Ф-строки (долги без носителя, найдены свипом 14.08) - **RTL-проверка:** триггер «появление I18nProvider» НАСТУПИЛ в S3.7 — строка с честной ценой. - **Спойлер достаётся в обход:** размытие глифов не прячет текст от поиска по странице (Ctrl+F) и печати в PDF — продуктовое слово нужно, строка + В-вопрос владельцу. - **Канвас-замер ширин не знает `lang`:** при двух CJK-лицах один код-пойнт рендерится по-разному — строка с условием срабатывания. Плюс одно закрытие по слову владельца 14.08 — **Ф-52:** поднять `--color-danger` на ступень до ≥3:1 на полотне панели (тот же приём, что у `--color-note` 2.98→3.07 в S3.7 — минимальный сдвиг тона, не редизайн), пере-прогнать axe, закрыть строку замером. ## 9. На владельце — НЕ решать и не трогать В-7 (плотность интерфейса; держит Ф-54 — обрезку центра на зуме: ЧИСЛО печатай, не чини) · В-8 (слово состояния в дереве) · В-9 (языки интерфейса) · В-4/Ф-30 (глава без заголовка — «на экране ничего не менять», ждёт и строку 160 движка) · Ф-38 (вкладка «Замечания») · К-13/Ф-31 (различение причин паузы) · В-3/В-6 (фразы ступени и паузы) · граница ПТ-33 (добавочные поля `BankTerm` — форм не выдумывать). Фразы PD-173 — исключение: их пишешь ты (§2), владелец утверждает по отчёту. Пины `STACK_DECISIONS` не двигать (Ф-28 — измерено и передано, не патчить). ## 10. Границы скоупа Подпись банка и его редактирование — S5. Читалка — S6. Экспорт, настройки (вкл. страницу лимитов), светлая тема — S7. Живого канала банка нет (строка 169 единого — гейт S5). **Добавление ГЛАВЫ (§3.10 промта зоны) не строить:** ручки в контракте не существует — кнопка без действия запрещена нормой зоны; счёл нужным — предложи черновиком правки спеки с пингом, не кодом. Мок-слой остаётся домом фронта (Ф-29 — триггер сноса не наступил); **опционально**, если локальный стенд платформы поднимется без боя — smoke живого `POST /books` через dev-прокси (same-origin, В-кватер; переключатель `TM_PLATFORM` дев-сервера уже существует — S3 чинила его достижимость) с честным отчётом; это НЕ гейт сдачи, со стендом не воюй, и помни каветы §4 про П-15: живой стенд местами отстаёт от контракта — эталон формы всегда спека, не стенд. ## 11. Самопроверка и сдача (мандат, не пожелание) - **Ревью исполнением:** каждый экранный путь прогнан живым браузером (скриншот-цикл/сценарии), каждый новый гейт и тест проверен ЖИВЫМ нарушением, тесты фиксов падают на до-фиксном коде. Вердикт о поведении браузера без живого прогона = PLAUSIBLE, не факт (D39.129). - **Адверсариальное ревью диффа — механизмом, author≠reviewer:** независимые ревью-агенты по диффу с установкой опровергать; субагенты/параллельные агенты для этого **разрешены явно** — дефолт-запреты харнесса на этот пункт не распространяются. Артефакт — таблица «находка → диспозиция» в записи журнала; «перечитал внимательно сам» исполнением НЕ считается. - **Предметные оси ревью этого пака** (вправе добавить свою или аргументированно снять): (1) контракт — каждая форма данных из спеки, новая потребность = черновик правки спеки, не фикстура (класс «фикстура выдумала форму» ловился четырежды); (2) доступность — axe на новых экранах/сценах, полный путь загрузки и шкала потолка проходимы клавиатурой; (3) статусные ветки — каждая (uploading/parsing/rejected по причинам/404/408/413/409/paused) показана сценой или кадром, не только тестом. - **Заявление = команда:** каждое число отчёта — с командой, которой получено; «сделано» без прогона не писать; чего НЕ сделал/не удалось — отдельным явным списком. - Гейты не подгонять: порог/проверку не двигать ради зелени; несогласие с гейтом — пинг. - Сдача: `npm run check` и `npm run check:full` зелёные; новые сцены в батарее; запись в `frontend/docs/frontend-PROGRESS.md` (механика, замеры, диспозиции всех находок §6, В-вопросы); BACKLOG обновлён; дерево НЕ коммитить — лендит оркестратор. ## 12. Канал вопросов Непонятно / промт конфликтует с кодом или доками / нужна правка вне `frontend/` → пинг оркестратору через владельца и запись в зонный журнал; НЕ интерпретация и НЕ правка чужой зоны. Настоящие развилки эскалируй быстро — это норма, а не слабость.