Add S3 handoff prompt gated on the API contract with F-14 fallback, plus new backlog row for unknown-value branches in closed unions
This commit is contained in:
parent
e6147d5aa4
commit
8b6f107cfa
3 changed files with 183 additions and 0 deletions
|
|
@ -21,6 +21,7 @@
|
|||
| Ф-17 | **Закрытие вкладки с клавиатуры не объявлено скринридеру.** Крестик у вкладки-документа сознательно НЕ кнопка: у роли `tab` дети презентационные (ARIA), вложенный фокусируемый элемент выпал бы из дерева доступности, оставшись в порядке табуляции (это же ловит axe правилом `nested-interactive`). Мышь закрывает крестиком, клавиатура — `Delete` на выбранной вкладке. Объявить сочетание нечем: `aria-keyshortcuts` не входит в типизированный API `Tab`/`TabList` в react-aria-components 1.20.0. Пересмотреть при обновлении библиотеки либо при появлении палитры команд | триггер: мажор RAC или экран горячих клавиш | S2 |
|
||||
| Ф-19 | **Переключение вкладки размонтирует её содержимое, и прокрутка длинного списка теряется.** Нашло адверсариальное ревью S2 и подтвердило независимым прогоном: `react-aria-components` не рендерит невыбранную `TabPanel` (`dist/private/Tabs.mjs:276` — `if (!isSelected && !shouldForceMount) return null`), поэтому на `/scale` прокрутка дерева `scrollTop=9000` → вкладка «Поиск» → обратно даёт `scrollTop=0`, а пересборка коллекции из 2284 узлов стоит 70–140 мс (два независимых замера). Ф-12 это не переоткрывает: там речь про поведение списка при 10³, и оно держится. **Чинить сейчас не стали:** `shouldForceMount` не лечит (панель остаётся видимым `div` и легла бы поверх соседней в той же ячейке грида), а настоящее лекарство — keep-alive либо запоминание офсета на вкладку — это решение об устройстве оболочки, и принимать его вслепую, до настоящих экранов, значит строить механизм не под задачу | S4 (экран глав) либо раньше, если владелец увидит потерю места | адверсариальное ревью S2 |
|
||||
| Ф-20 | **Мёртвый шрифт и мёртвые токены в поставке.** `@fontsource-variable/jetbrains-mono` грузится в бандл, но `--font-mono` не выбран ни одним правилом: художественную прозу моноширинным не набирают, а во Fleet на этом месте был код. Туда же несколько токенов, которые ни разу не используются (`--color-current-line`, `--color-hint`). Замок полноты токенов (S2) требует классифицировать токен, но не требует его использовать. Решать на S6, когда читалка станет настоящей: либо моноширинный находит работу, либо импорт и токены уходят | S6 | адверсариальное ревью S2 |
|
||||
| Ф-22 | **У закрытых юнионов нет ветки неизвестного значения, и тайпчек здесь не страхует.** `runStates[book.state]` (`showcase/Library.tsx:103`) — обращение к `Record` по КОНЕЧНОМУ юниону, а `noUncheckedIndexedAccess` добавляет `undefined` только индексным сигнатурам: проверено пробой `tsc` — обращение по юниону компилируется молча, ругается лишь `Record<string, …>`. Значение вне юниона (новое состояние прогона из контракта API) даёт `undefined.tone`, то есть падение дерева библиотеки, а не пустую метку; тем же классом `noteTone` тихо уводит незнакомую ступень замечания в спокойную ветку. Лечение — ветка неизвестного значения НА ШВЕ `src/api/`, где значение входит, а не в каждом компоненте. В S2 находку отвели скептики формулировкой «это работа S3» — она и есть работа S3, но хвост записан здесь, чтобы не жить только в промте | S3 (вместе с приведением типов к контракту) | адверсариальное ревью S2 → ревью оркестратора 04.08 |
|
||||
| Ф-21 | **Ступень замечания различается только цветом полоски** (`attention` синяя, `glance` серая). Зрячему разница читается ещё и светлотой, но скринридеру приоритет не достаётся вовсе. Лечение — слово, как это уже сделано для состояния прогона книги; **какое именно слово, решает владелец**: словарь замечаний продуктовый (ПТ-33), а §3.8 требует, чтобы экран не выглядел тревожным, так что «важно/неважно» не годится | решение владельца | адверсариальное ревью S2 |
|
||||
| Ф-18 | **Бандл 545 КБ (168 КБ gzip) одним куском** — замер 04.08 после установки `react-aria-components`; Rolldown предупреждает про порог 500 КБ. Для десктопного SPA за логином это не авария (индексации нет, сеть локальная), но одним куском едут и экраны, которых пользователь ещё не открыл. Лечение — разбиение по маршрутам, и делать его осмысленно после S4–S7, когда экраны появятся: сейчас резать нечего | после S7 либо при жалобе на первый экран | S2, замер |
|
||||
| Ф-5 | **Tauri 2.x вторым шагом** — по явным триггерам (трей · глобальные горячие клавиши · распространяемый .exe · офлайн · хранилище учёток ОС); до того — установимое PWA, только браузерные API | триггеры названы | STACK_DECISIONS §6, D39.84 |
|
||||
|
|
|
|||
|
|
@ -22,6 +22,9 @@
|
|||
по ревью оркестратора 04.08 добавлены динамические импорты швов и языковая ветка в CSS.
|
||||
- **Карта канона для фронт-сессии — `FRONTEND_PLAN.md` §0.1, транспорт — §0.2.** Заведены
|
||||
после того, как две ошибки S1 пришли из непрочитанного канона; читать до кода, не после.
|
||||
- **Передача следующей сессии написана — `S3_SESSION_PROMPT.md`** (сессией S2 по просьбе
|
||||
владельца; ратифицирует оркестратор): вход в S3 под замком контракта API, который сессия
|
||||
проверяет сама, плюс фолбэк на Ф-14, если замок закрыт, и перечень ловушек, купленных S2.
|
||||
- **Гейты стоят и на коммите:** pre-commit хук (02.08, вторая сессия) гоняет `npm run check`
|
||||
для коммитов с frontend-путями и блокирует смесь зон и файлы «никогда не коммитить»;
|
||||
ставится сам при `npm install`. Обход — только осознанный `git commit --no-verify`.
|
||||
|
|
|
|||
179
frontend/docs/S3_SESSION_PROMPT.md
Normal file
179
frontend/docs/S3_SESSION_PROMPT.md
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
# Промт: фронт-сессия 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-модулей.
|
||||
- ⚠ **На момент написания промта в дереве лежали незакоммиченные правки** по ревью оркестратора
|
||||
(`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.md`?
|
||||
2. Что говорит строка **95** единого бэклога в `docs/PROGRESS.md` (контракт API v0 + продуктовый
|
||||
словарь статусов) — она всё ещё «дизайн-промт по слову владельца» или уже исполнена?
|
||||
|
||||
**Открыт** (контракт есть и ратифицирован) → скоуп S3 ниже.
|
||||
**Закрыт** (на 04.08 — закрыт: файла нет) → раздел «Если замок закрыт». Не начинай S3 «пока
|
||||
на своих типах, потом поправим»: моки, снятые не с того контракта, разойдутся с API — ровно
|
||||
то, ради чего строка 95 заведена.
|
||||
|
||||
## Обязательное чтение до кода (порядок)
|
||||
|
||||
1. `frontend/docs/FRONTEND_SESSION_PROMPT.md` — стоящий промт: сценарий §3, жёсткие ограничения
|
||||
§4, «как работать» §7. **Его не редактировать.** ⚠ Раскладка §2 частично устарела — её
|
||||
перевешивают решения владельца из журнала зоны.
|
||||
2. `frontend/docs/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 — слой данных, и ни шагом дальше
|
||||
|
||||
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. **Поля не выдумывать.** Нет в контракте — это вопрос владельцу/оркестратору в
|
||||
«Открытые вопросы» журнала зоны, а не догадка в типе. Дефект «фикстура выдумала поле»
|
||||
в этой зоне случался дважды и оба раза стоил экрана.
|
||||
|
||||
**Не в скоупе:** экраны S4–S7 · редактор текста · светлая тема · мобильная раскладка ·
|
||||
React Compiler (Ф-2) · Tauri (Ф-5).
|
||||
|
||||
## Если замок закрыт
|
||||
|
||||
Это ожидаемое состояние на 04.08, и правильный ход — не ждать молча и не строить экраны
|
||||
на синхронных моках (порядок этапов Ф-1 стоит именно на слое данных).
|
||||
|
||||
- **Доведи Ф-14 до артефакта, который можно отдать автору контракта:** не список намерений,
|
||||
а перечень с обоснованием на каждый пункт — язык кодами · состояние прогона отдельно от
|
||||
выполнения главы · прогресс пофазно по ЮНИТАМ · ревизия/`Last-Event-ID` · трёхзначный статус
|
||||
подписи · поля банка (`type`/`sense`/`since_ch`) и ключ строки · продуктовый словарь вердиктов
|
||||
(ПТ-33; §4.1 запрещает протечку внутренностей конвейера на экран). Половина уже написана
|
||||
в строке Ф-14 и в §6 плана — собери, а не сочиняй заново.
|
||||
- Отдай его оркестратору пингом в `docs/PROGRESS.md` и **остановись**: заводить контракт своим
|
||||
решением фронт не может (шапка `BACKLOG.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/PROGRESS.md`: обновлено «Текущее состояние», добавлена хроника сессии
|
||||
(что построено · что видно на снимках · где отошёл от канона и почему · что осталось);
|
||||
строки бэклога получили диспозиции.
|
||||
- Ничего не закоммичено: дерево подготовлено и передано оркестратору.
|
||||
|
||||
## Что ждёт не тебя (не решай сам)
|
||||
|
||||
**В-1** данные привязаны к одной машине (вопрос на движок/платформу) · **В-2** копирайт фикстур ·
|
||||
**В-3/Ф-21** каким словом называть ступень замечания (словарь продуктовый, ПТ-33) ·
|
||||
**Ф-11** контраст палитры ниже WCAG на четырёх узлах — принято как есть до слова владельца.
|
||||
Loading…
Add table
Reference in a new issue