textmachine/frontend/docs/S3_SESSION_PROMPT.md

22 KiB
Raw Blame History

Промт: фронт-сессия S3 — слой данных (вход под замком)

Ты — фронтенд-сессия TextMachine, четвёртая по счёту. Зона записи — только frontend/; сессия не коммитит — лендит оркестратор (протокол — стоящий промт FRONTEND_SESSION_PROMPT.md §«Зона и git», он в силе целиком). Пре-коммит хук стоит и самоустанавливается при npm install.

Промт написан сессией S2 по просьбе владельца — как передача с той точки, где S2 встала. Ратифицирует и правит его оркестратор; при расхождении с его хендофф-промтом побеждает тот.

Входное состояние (04.08, проверено исполнением, а не заявлено)

  • Пройдено S0S2: план · инструменты и скриншот-цикл · 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-модулей.
  • На момент написания промта в дереве лежали незакоммиченные правки по ревью оркестратора (frontend/src/{api/types.ts,generality.test.ts,mock/book.ts,mock/scale.ts,showcase/Context.tsx, showcase/Reader.module.css,tokens/tokens.css,tokens/tokens.test.ts}, eslint.config.js, frontend/docs/*). Их лендит оркестратор. Первым делом сверься с git log и git status: если правок в дереве нет — они уже уехали, ничего восстанавливать не нужно.

Замок на входе — первое действие сессии

Проверь сам, промту не верь (он написан 04.08 и мог устареть):

  1. Существует ли docs/architecture/14-api-contract/ (спека + компаньон)? — на 04.08 вечера: ДА, ратифицирован (D39.99), замок ОТКРЫТ;
  2. Строки 95 в таблице единого бэклога больше НЕТ — она ЗАКРЫТА (D39.99, закрытые строки уходят в D-лог); если видишь её живой — дерево старее канона, стоп и пинг.

Открыт (контракт есть и ратифицирован) → скоуп S3 ниже. Закрыт → раздел «Если замок закрыт» (контингенция; на вечер 04.08 замок ОТКРЫТ — D39.99). Не начинай S3 «пока на своих типах, потом поправим»: моки, снятые не с того контракта, разойдутся с 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.mddocs/README.md требует читать его перед любым кодом стыка; форма событий и правило ре-синка оттуда.
  6. frontend/docs/BACKLOG.md — строки Ф-14 (вход фронта в контракт), Ф-15 (закрывается этой сессией), Ф-19, Ф-21.
  7. references/*.png и .shots/*.png — открой и посмотри до первой правки.

Решения владельца 04.08 вечер (D39.100) — правки спеки ПЕРВЫМ шагом S3

Контракт ратифицирован, четыре К-вопроса закрыты владельцем; спеку правишь ты (минорный бамп версии, регенерация типов, батарея), компаньон-К-таблицу — статусами «решено»:

  1. К-1 закрыт: десять статусов приняты.
  2. К-8 закрыт механизмом «как Claude Code» (ПТ-35, П-5): BookStatus получает 11-е значение paused (стоп по потолку; резюмируемый; в failed не мапить — уже запрещено спекой); пользователь видит оповещение «перевод остановлен: лимиты исчерпаны», сами лимиты — страница в настройках (СТАТУС использования, не суммы: запрет денег на проводе в силе). API лимитов проектирует платформа (П-5) — поле/эндпоинт в спеку НЕ выдумывать, только статус и семантику оповещения.
  3. К-5 закрыт: ETA показыватьeta_seconds в прогресс-модель (движок отдаёт, status.go:112; поле опциональное — оценка бывает недоступна).
  4. К-3 закрыт с канон-уточнением: метка главы — ИЗ ДАННЫХ книги, зашитых форм нет. «Глава N» — это шаблон langpack-ДАННЫХ, не закон: легальна книга вовсе без номеров и глав. Дерево рендерит label, который дал манифест (строка 100)/heading (К-2), внутренний порядок — непрозрачный индекс. Проверь спеку и фикстуры на зашитую форму «Глава N».
  5. После правок: байт-сверка зонной спеки с ратифицированной копией (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<string, …>). Значит состояние прогона из будущего контракта даёт undefined.tone — падение дерева библиотеки, а не пустую метку; noteTone тем же классом тихо уводит незнакомую ступень замечания в СПОКОЙНУЮ ветку. Место ветки — шов src/api/, где значение входит, а не каждый компонент: перевод «вердикт → вид» уже расползался по экранам, и контрольный вопрос владельца требует, чтобы новое значение правило один файл.
  6. Поля не выдумывать. Нет в контракте — это вопрос владельцу/оркестратору в «Открытые вопросы» журнала зоны, а не догадка в типе. Дефект «фикстура выдумала поле» в этой зоне случался дважды и оба раза стоил экрана.

Не в скоупе: экраны S4S7 · редактор текста · светлая тема · мобильная раскладка · 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; раскрытие — <Button slot="chevron"> · renderEmptyState обёрнут в role="option" (зонд S2 принял это за дефект кода).
  • react-resizable-panels v4: className/style панели уезжают во ВЛОЖЕННЫЙ div, у него всегда inline overflow:auto · Separator обязан быть прямым ребёнком Group · ключ хранилища раскладки содержит состав видимых панелей, поэтому сворачивание удалением панели меняет ключ (сделано осознанно: так поле оболочки остаётся ровно замеренным).
  • Скриншот-цикл: vite build и preview в один момент дают пустой экран — это гонка, а не регрессия; перезапусти прогон, прежде чем «чинить» рабочий код.
  • Зонды и живые нарушения: файлы зондов удалять за собой (в S2 агенты ревью оставили свои в чужом дереве), правленые файлы восстанавливать из памяти процесса, а не git checkout — в дереве могут лежать незакоммиченные правки параллельных сессий.
  • Первому красному результату зонда не верить: три «находки» первого прогона S2 оказались дефектами зонда (селектор бил по трём панелям сразу), и соблазн «починить» рабочий код был вполне реальный.
  • esquery: селектор вида Property[key.value=/^--/] > Literal[…] ловит собственный ключ свойства — в TSX-гейте это записано комментарием, не убирай его.

Технические рамки

  • Новый маршрут → сразу в KNOWN_ROUTES (scripts/shot.mjs); тест сверяет списки и упадёт.
  • Гейты не ослаблять. Точечное подавление — только именованное правило с причиной.
  • Файл = компонент + модуль стилей рядом; >150 строк — делить. Комментарии — одна-две строки «почему», не «что».
  • Тексты фикстур — настоящие пропорции кириллицы и иероглифов, объём минимальный: вопрос авторского права (В-2) у владельца, цитаты не расширять.

Как работать

  1. Ревью исполнением — мандат проекта, не пожелание: приложение поднимается, скриншоты сняты и ПРОСМОТРЕНЫ, каждый гейт проверен живым нарушением с перечнем форм, npm run check:full зелёный. «Должно работать» ревью не является.
  2. Скриншот-цикл — с первого изменения, критерий сведения — не растровое совпадение, а плотность и впечатление (стоящий промт §8).
  3. Адверсариальная самопроверка перед финишем (author≠reviewer): пройди по своим правкам с установкой опровергать. S1 так поймала пять дефектов в собственных гейтах, S2 — восемь.
  4. Спорное с каноном или новое продуктовое решение не принимай сам: вопрос в «Открытые вопросы к владельцу» журнала зоны, и продолжай то, что вопроса не требует.

Готово — это когда

  • Замок проверен и результат записан: либо S3 сделана, либо в журнале лежит, чем сессия занималась вместо неё и почему.
  • Если S3 сделана: src/api/ асинхронен, MSW отдаёт все состояния, ветки ожидания/ошибки/пустоты живые, Ф-15 закрыта, типы сведены с контрактом, а расхождения — не «поправим потом», а строки бэклога с триггером.
  • npm run check:full зелёный; новые маршруты в shot.mjs; скриншоты просмотрены.
  • frontend/docs/frontend-PROGRESS.md: обновлено «Текущее состояние», добавлена хроника сессии (что построено · что видно на снимках · где отошёл от канона и почему · что осталось); строки бэклога получили диспозиции.
  • Ничего не закоммичено: дерево подготовлено и передано оркестратору.

Что ждёт не тебя (не решай сам)

В-1 данные привязаны к одной машине (вопрос на движок/платформу) · В-2 копирайт фикстур · В-3/Ф-21 каким словом называть ступень замечания (словарь продуктовый, ПТ-33) · Ф-11 контраст палитры ниже WCAG на четырёх узлах — принято как есть до слова владельца.