Amend issued S3.7 prompt after owner review: F-35 i18n task added as caught omission, industry i18n mechanism required, journal pointers synced

This commit is contained in:
heaven 2026-08-10 23:52:20 +03:00
parent 57e6bd1d63
commit 7f3798db0f
2 changed files with 125 additions and 5 deletions

View file

@ -14,8 +14,10 @@
> живой поток идёт по SSE (`src/showcase/useRunStream.ts`), чтения — TanStack Query > живой поток идёт по SSE (`src/showcase/useRunStream.ts`), чтения — TanStack Query
> (`src/api/queries.ts`), контракт — зонная копия `frontend/docs/api-contract/openapi.yaml` > (`src/api/queries.ts`), контракт — зонная копия `frontend/docs/api-contract/openapi.yaml`
> (0.2.1), типы генерятся из неё. Эта сессия НЕ строит новых экранов: она закрывает названный > (0.2.1), типы генерятся из неё. Эта сессия НЕ строит новых экранов: она закрывает названный
> техдолг слоя данных (Ф-49…Ф-51), одну ратифицированную правку контракта (Ф-47) и мелкие > техдолг слоя данных (Ф-49…Ф-51), одну ратифицированную правку контракта (Ф-47),
> хвосты. S4 стартует после неё отдельным промтом. По всем задачам — прогон в отчёте; > интернационализацию строк интерфейса (Ф-35: словарь + гейт, без хардкода русского)
> и мелкие хвосты. S4 стартует после неё отдельным промтом.
> По всем задачам — прогон в отчёте;
> **молча пропустить задачу нельзя**: сделано / диспозиция с обоснованием / вопрос В-строкой. > **молча пропустить задачу нельзя**: сделано / диспозиция с обоснованием / вопрос В-строкой.
## Обязательное чтение до кода (порядок) ## Обязательное чтение до кода (порядок)
@ -180,6 +182,30 @@ text arrives with a read after the boundary»).
- `BACKLOG.md` Ф-47 — «`?? ''` в трёх местах» завышено: вхождение одно - `BACKLOG.md` Ф-47 — «`?? ''` в трёх местах» завышено: вхождение одно
(`src/showcase/Bank.tsx:166`); поправить при закрытии строки. (`src/showcase/Bank.tsx:166`); поправить при закрытии строки.
### 9. Ф-35 — строки интерфейса без хардкода: словарь + гейт
Сегодня ~90 русских литералов живут прямо в разметке (Ф-35); локаль примитивов уже сведена
в одно место (`src/ui/Locale.tsx`, `interfaceLocale`). Сделать интерфейс переводимым
МЕХАНИЗМОМ, не переводом:
- все строки интерфейса уезжают в КАТАЛОГ сообщений, механизм — ОТРАСЛЕВОЙ i18n-инструмент,
не самописная поделка: компонент берёт строку по ключу, локаль = данные, новый язык
добавляется файлом перевода без захода в компоненты. Кандидатов сравнить и выбор обосновать
в журнале (у react-aria уже есть свой слой `@internationalized/string`; react-intl / lingui —
альтернативы); новая зависимость — с точным пином и записью в `STACK_DECISIONS.md` §3,
как того требует политика пинов; цену бандла замерить;
- **гейт против нового хардкода:** кириллический литерал в JSX/разметке = ошибка линта
(исключения — модуль словаря и фикстуры); гейт проверить ЖИВЫМ нарушением, как Ф-4/Ф-9;
- хранилище выбора языка подключить к словарю; каркасный пункт настроек «язык интерфейса»
уже есть — честное состояние «сейчас интерфейс только русский» остаётся, пока локаль
содержимого одна (ru);
- границы прежние: фикстурная проза (тексты мок-книг, названия глав, термины банка) — ДАННЫЕ,
не интерфейс, в словарь не уезжает; продуктовый список языков — решение владельца (если
нужен ответ сейчас — В-строкой); переводы строк на другие языки НЕ выдумывать.
Приёмка: гейт ловит подсунутый литерал (показать нарушением); кадры семи маршрутов
не изменились — это переезд строк, не перевод.
## Что НЕ делать ## Что НЕ делать
- Не строить экраны S4S7 (загрузка книги, механизм подписи, содержимое настроек, экспорт). - Не строить экраны S4S7 (загрузка книги, механизм подписи, содержимое настроек, экспорт).
@ -204,5 +230,6 @@ text arrives with a read after the boundary»).
адверсариальное ревью диффа (author≠reviewer) в конце; находки с диспозициями — в журнал. адверсариальное ревью диффа (author≠reviewer) в конце; находки с диспозициями — в журнал.
- Прогон по всем задачам таблицей в `frontend-PROGRESS.md`: задача → что сделано → тест/замер → - Прогон по всем задачам таблицей в `frontend-PROGRESS.md`: задача → что сделано → тест/замер →
либо диспозиция. Хвосты — строками Ф-N в `BACKLOG.md` (Ф-49/50/51/40/47 закрыть или либо диспозиция. Хвосты — строками Ф-N в `BACKLOG.md` (Ф-49/50/51/40/47 закрыть или
переформулировать честно), вопросы владельцу — В-строками. переформулировать честно; Ф-35 и Ф-25 закрываются в своей код-половине, продуктовая половина
Ф-35 «какие языки» остаётся на владельце), вопросы владельцу — В-строками.
- Промт S4 не писать — его выдаёт оркестратор после приёмки этого пака. - Промт S4 не писать — его выдаёт оркестратор после приёмки этого пака.

View file

@ -103,6 +103,18 @@
> ресёрчу отдельным агентом и проверены по коду; два моих собственных предложения тот же ресёрч > ресёрчу отдельным агентом и проверены по коду; два моих собственных предложения тот же ресёрч
> опроверг, и это записано в разделе 15 вместе с долгами сессии. > опроверг, и это записано в разделе 15 вместе с долгами сессии.
> **Запись фронт-сессии S3.7, 10.08.** Долги слоя данных закрыты тестами, падающими на до-фиксном
> коде (Ф-49…Ф-51), контракт зонной копии бампнут до **0.2.2** (`BankTerm.sense` обязателен),
> строки интерфейса уехали в КАТАЛОГ (`src/i18n/`, 147 ключей, механизм — `@internationalized/string`,
> уже лежавший в дереве под react-aria-components), и весь код зоны переведён на английский:
> комментарии, имена тестов, сообщения ошибок, логи скриптов. Держат это два гейта, и каждый
> проверен ЖИВЫМ нарушением — ESLint ловит текст в разметке МЕСТОМ, а не алфавитом (ловит и русский,
> и английский литерал), `src/i18n/catalogue.test.ts` подметает комментарии, CSS и python.
> `npm run check` зелёный: **266 тестов** (было 160), `npm run check:full` — 7 маршрутов и
> **9 сценариев** (добавлены `hidden` и `zoom`: раскладка при 125/150/200% с прогоном axe).
> ⚠ Находка приёмки 8.1 (HIGH) **не воспроизвелась** — замер в браузере в записи ниже, механизм,
> написанный было под неё, снят; сценарий на тот же путь оставлен сторожем (Ф-53).
> **Четвёртый круг замечаний, 10.08 (раздел 12 хроники).** Четыре бага владельца по таблице банка > **Четвёртый круг замечаний, 10.08 (раздел 12 хроники).** Четыре бага владельца по таблице банка
> закрыты, и один из них был МОЙ механизм: заморозка ширин (`useSettledWidth`) оставляла таблицу > закрыты, и один из них был МОЙ механизм: заморозка ширин (`useSettledWidth`) оставляла таблицу
> сжатой после драга, а перезамер показал, что она ничего не покупала — драг держит p90 17 мс и > сжатой после драга, а перезамер показал, что она ничего не покупала — драг держит p90 17 мс и
@ -115,8 +127,10 @@
> **Запись оркестратора, 10.08 — ПРИЁМКА S3.6: принято и залендено (D39.127).** Гейты > **Запись оркестратора, 10.08 — ПРИЁМКА S3.6: принято и залендено (D39.127).** Гейты
> пере-прогнаны исполнением, 12 находок ревью (1 high) и поправки к записи S3.6 — первой записью > пере-прогнаны исполнением, 12 находок ревью (1 high) и поправки к записи S3.6 — первой записью
> хроники ниже. Промт **S3.7** выдан (`S37_SESSION_PROMPT.md`: Ф-49…Ф-51, Ф-47 ратифицирован, > хроники ниже. Промт **S3.7** выдан (`S37_SESSION_PROMPT.md`: Ф-49…Ф-51, Ф-47 ратифицирован,
> Ф-40, Ф-25, находки §8), запуск по слову владельца; **S4 — после приёмки S3.7.** Экспорт банка > Ф-40, Ф-25, Ф-35 — словарь строк + гейт против хардкода русского; ⚠ Ф-35 в первой редакции
> заведён строкой 169 единого бэклога (Ф-43). > промта отсутствовала — пропуск поймал владелец при ревью промта, D39.127 п.2г), запуск
> по слову владельца; **S4 — после приёмки S3.7.** Экспорт банка заведён строкой 169
> единого бэклога (Ф-43).
- **Пройдено:** S0 (план), S1 (инструменты, скриншот-цикл, `tokens.css`, витрина), - **Пройдено:** S0 (план), S1 (инструменты, скриншот-цикл, `tokens.css`, витрина),
S2 (оболочка трёх панелей, слой `src/ui/`, масштаб списков, хвосты гейтов), S2 (оболочка трёх панелей, слой `src/ui/`, масштаб списков, хвосты гейтов),
@ -345,12 +359,91 @@ NDJSON — это шов ДВИЖОК↔ПЛАТФОРМА (D39.85), а фрон
| В-6 | **Упёрся в свой потолок ≠ кончились деньги, а интерфейс их не различает.** Владелец 07.08 дал человеку поставить перед стартом колпак в ГЛАВАХ; платформа берёт холд на его сумму. Но машинная причина паузы в контракте ровно одна — `credit_exhausted`, и она про кредит. Значит прогон, честно доехавший до выбранной человеком границы, и прогон, у которого кончился баланс, приходят на экран одной фразой «перевод остановлен: лимиты исчерпаны». Первому она врёт: лимит не исчерпан, человек сам так решил, и следующее действие у него другое — поднять колпак, а не пополнить счёт. Нужно ли второе значение и какая у него фраза — продуктовое. Заведено К-13, строка Ф-31 | продуктовая формулировка, которую видит пользователь, и разное следующее действие | | В-6 | **Упёрся в свой потолок ≠ кончились деньги, а интерфейс их не различает.** Владелец 07.08 дал человеку поставить перед стартом колпак в ГЛАВАХ; платформа берёт холд на его сумму. Но машинная причина паузы в контракте ровно одна — `credit_exhausted`, и она про кредит. Значит прогон, честно доехавший до выбранной человеком границы, и прогон, у которого кончился баланс, приходят на экран одной фразой «перевод остановлен: лимиты исчерпаны». Первому она врёт: лимит не исчерпан, человек сам так решил, и следующее действие у него другое — поднять колпак, а не пополнить счёт. Нужно ли второе значение и какая у него фраза — продуктовое. Заведено К-13, строка Ф-31 | продуктовая формулировка, которую видит пользователь, и разное следующее действие |
| В-8 | **Какое слово о состоянии книги стоит в дереве.** Замечание 23 потребовало бейджу ФИКС-место, и оно сделано; но две метки словаря в него не помещаются и усекаются с тултипом — «остановлена: лимиты» (19 знаков) и ветка неизвестного «неизвестное состояние» (21). Укоротить их сессия НЕ вправе: фраза паузы зарезервирована за владельцем (В-6), и первый заход S3.5 её укоротил и был откачен собственным ревью. Варианты: (а) оставить усечение с тултипом, (б) владелец даёт короткое слово для дерева, а полная фраза остаётся в статус-полосе, (в) расширить колонку бейджа за счёт названия книги | продуктовая формулировка, которую видит пользователь | | В-8 | **Какое слово о состоянии книги стоит в дереве.** Замечание 23 потребовало бейджу ФИКС-место, и оно сделано; но две метки словаря в него не помещаются и усекаются с тултипом — «остановлена: лимиты» (19 знаков) и ветка неизвестного «неизвестное состояние» (21). Укоротить их сессия НЕ вправе: фраза паузы зарезервирована за владельцем (В-6), и первый заход S3.5 её укоротил и был откачен собственным ревью. Варианты: (а) оставить усечение с тултипом, (б) владелец даёт короткое слово для дерева, а полная фраза остаётся в статус-полосе, (в) расширить колонку бейджа за счёт названия книги | продуктовая формулировка, которую видит пользователь |
| В-7 | **Физический масштаб интерфейса на мониторе.** Замечание 1 говорит «масштабы великоваты, особенно на 27″ 2K, на 24″ терпимее». Замер при вьюпорте референса расхождения с Fleet не нашёл (§5.5 плана): промежутки, ширины панелей, шаг строки и высота вкладки совпадают. Значит речь про физический размер на конкретном экране, а он зависит от масштабирования ОС, и «просто уменьшить токены» означало бы уехать от референса, который владелец принял. Правильное лекарство — ручка «плотность интерфейса» в настройках (3 ступени), но она требует перевода ВСЕХ размерных токенов в rem и пере-замера, то есть отдельного прохода (Ф-36). Вопрос: нужна ли ручка, и какой масштаб ОС стоит на 27″ 2K — по нему видно, во сколько раз расходится физика | продуктовое решение и цена отдельного пакета | | В-7 | **Физический масштаб интерфейса на мониторе.** Замечание 1 говорит «масштабы великоваты, особенно на 27″ 2K, на 24″ терпимее». Замер при вьюпорте референса расхождения с Fleet не нашёл (§5.5 плана): промежутки, ширины панелей, шаг строки и высота вкладки совпадают. Значит речь про физический размер на конкретном экране, а он зависит от масштабирования ОС, и «просто уменьшить токены» означало бы уехать от референса, который владелец принял. Правильное лекарство — ручка «плотность интерфейса» в настройках (3 ступени), но она требует перевода ВСЕХ размерных токенов в rem и пере-замера, то есть отдельного прохода (Ф-36). Вопрос: нужна ли ручка, и какой масштаб ОС стоит на 27″ 2K — по нему видно, во сколько раз расходится физика | продуктовое решение и цена отдельного пакета |
| В-9 | **Какие языки интерфейса продукт обещает.** Механизм переводимости построен (S3.7, Ф-35): слова интерфейса живут в каталоге `src/i18n/ru.ts`, второй язык — второй файл того же вида плюс строка в `src/i18n/language.ts`, ни один компонент при этом не трогается. Чего фронт сделать не может и не должен: решить, какие языки продукт обещает, и выдумать сами переводы. Пока список из одного значения (`ru`), и каркасный пункт настроек честно говорит «сейчас интерфейс только русский» | продуктовое решение и обещание пользователю |
| В-2 | **Авторское право на текст фикстур.** Витрина использует короткую выдержку из настоящего прогона (蛊真人). Правило проекта уже есть: `eval/.gitignore:4` держит копирайтные тексты вне git. Сейчас взят объём под проверку плотности и не больше; нужно ли убрать совсем и заменить синтетикой — решать владельцу | юридика | | В-2 | **Авторское право на текст фикстур.** Витрина использует короткую выдержку из настоящего прогона (蛊真人). Правило проекта уже есть: `eval/.gitignore:4` держит копирайтные тексты вне git. Сейчас взят объём под проверку плотности и не больше; нужно ли убрать совсем и заменить синтетикой — решать владельцу | юридика |
| В-4 | **Чем подписывать главу в дереве, если заголовок — ровно «Глава N».** Титул движок рендерит детерминистически из шаблона пары (`configs/langpacks/zh-ru/heading.txt`: `template Глава {n}`), а подзаголовок остаётся телом текста и названием НЕ является. На 2284 разделах это дерево из 2284 одинаковых по форме строк. Оставить так, показывать номер иначе или просить у контракта что-то ещё — продуктовое решение. Артефакт §1.4 и К-3 | продуктовая формулировка, которую видит пользователь | | В-4 | **Чем подписывать главу в дереве, если заголовок — ровно «Глава N».** Титул движок рендерит детерминистически из шаблона пары (`configs/langpacks/zh-ru/heading.txt`: `template Глава {n}`), а подзаголовок остаётся телом текста и названием НЕ является. На 2284 разделах это дерево из 2284 одинаковых по форме строк. Оставить так, показывать номер иначе или просить у контракта что-то ещё — продуктовое решение. Артефакт §1.4 и К-3 | продуктовая формулировка, которую видит пользователь |
| В-5 | **Показывать ли оценку времени до конца прогона.** У движка поле есть (`status.go` `eta_seconds`, «secondary: mean fresh-call throughput × remaining»), запретом §4.8 оно не покрыто (это не деньги), но и не запрошено ни одним разделом промта. Решать ДО формы прогресса, иначе поле придётся вводить задним числом в уже нарисованную полосу. Артефакт К-6, резерв строки 54 единого бэклога | продуктовое: обещание срока пользователю | | В-5 | **Показывать ли оценку времени до конца прогона.** У движка поле есть (`status.go` `eta_seconds`, «secondary: mean fresh-call throughput × remaining»), запретом §4.8 оно не покрыто (это не деньги), но и не запрошено ни одним разделом промта. Решать ДО формы прогресса, иначе поле придётся вводить задним числом в уже нарисованную полосу. Артефакт К-6, резерв строки 54 единого бэклога | продуктовое: обещание срока пользователю |
## Хроника ## Хроника
### 10.08 — восьмая фронт-сессия (S3.7): долги слоя данных, контракт 0.2.2, строки в каталог
Вход: промт `S37_SESSION_PROMPT.md` (девять задач) плюс правило владельца, пришедшее по ходу пака:
**в КОДЕ никакого русского** — комментарии, сообщения ошибок, логи, имена тестов, служебные строки
сценариев по-английски; русский UI-текст живёт ТОЛЬКО в словаре.
#### 1. Прогон по задачам
| Задача | Что сделано | Тест / замер |
|---|---|---|
| **Ф-49** свежесть текста главы | кадр `chapter` инвалидирует юниты ИМЕННО своей главы, кадр `status` — юниты всей книги (границы стадий: пока `units_done` единый счётчик, кадра главы за волну может не быть ни одного) | `useRunStream.test.tsx`, 2 случая по счёту запросов к MSW; оба падают на до-фиксном коде |
| **Ф-50** потерянный кадр | кадр, не нашедший снимка, зовёт `resetQueries` по своему ключу; ревизия многостраничного списка = МИНИМУМ из страниц | 2 теста, оба падают на до-фиксном коде. **Выбор reset вместо invalidate — замер, а не вкус:** `invalidateQueries` на запросе без данных ничего не делает (в исходнике библиотеки: перезапуск в полёте только при `state.data !== undefined`), то есть возвращает промис того самого устаревшего чтения |
| **Ф-51** resync | `resetQueries` по скоупу КНИГИ (`bookScope`), отметка ревизии уходит вместе со снимком; чужие скоупы целы | 2 теста, оба падают на до-фиксном коде |
| **Ф-47** `sense` обязателен | зонная копия `openapi.yaml`**0.2.2**, правило пустой строки в описании, типы перегенерены, костыль `?? ''` снят | `npm run contract` зелёный; ⚠ костыль был в ОДНОМ месте, а не в трёх — счёт строки бэклога был завышен |
| **Ф-40** общий модуль поля | `src/ui/Field.module.css` (`.input` + модификатор `.framed`), примитивы остались разными | `cssModules.test.ts` (пары по импортам, сироты) |
| **Ф-25** язык кода | английские комментарии/тесты/сообщения во ВСЁМ дереве зоны, включая конфиги, `index.html` и python | гейт `src/i18n/catalogue.test.ts`, проверен живым нарушением |
| **Ф-35** строки интерфейса | каталог `src/i18n/ru.ts` (147 ключей), механизм `@internationalized/string` 3.2.10, стор языка с персистом, локаль оттуда же берут `I18nProvider` и весь `Intl` | гейт ESLint проверен живым нарушением; цена бандла 716131 → 723102 (+6971 байт, из них ~7 КБ — сам текст) |
| **сторожа** зум и узкая панель | сцена `zoom` (125/150/200% = вьюпорты 1152/960/720 в CSS-пикселях): перелив окна, три панели, статус-полоса в окне, таблица банка не за краем, axe на каждом шаге | `npm run scenes zoom` — 20 проверок |
| **замер `measure.py`** | палитра S3.6 воспроизведена по `fleet_2.png` (`#181818` 63.97%, `#292929` 7.17%), кадр `/showcase` сведён с `fleet.png` при 1280×764 | числа и вердикты — `FRONTEND_PLAN.md` §5.7; окружение запинено (`scripts/requirements.txt`) |
#### 2. Находки приёмки S3.6
| № | Диспозиция |
|---|---|
| 8.1 (HIGH) | **НЕ ВОСПРОИЗВЕЛАСЬ.** Замер в браузере: таблица, смонтированная в скрытой keep-alive вкладке `/scale`, держит 116 ячеек и ширины `121·122·133·232` — те же, что у вкладки, с которой не уходили, и на до-фиксном коде тоже; `content-visibility: hidden` подтверждён на самой панели (`data-inert`, computed `hidden`). Причина: запрос геометрии внутри пропущенного поддерева заставляет браузер посчитать раскладку. Мой первый заход добавил под эту находку `IntersectionObserver`**механизм снят**, чинить нечего. Сцена `hidden` (уход с вкладки ДО прихода банка и возврат) оставлена сторожем: путь реален и не был покрыт. Строка Ф-53 |
| 8.2 контраст выбранной строки | починены пары на синем: счётчик и бейдж → `--color-text` (7.27:1), значок и дорожка → `--color-text-secondary` (3.52:1), заполнение → `--color-text` . Сторож в сцене `tabs` считает контраст ВНУТРИ страницы и падает на до-фиксном коде четырьмя парами (1.97 · 3.52 · 1.55 · 1.97). ⚠ Названо честно: пара «заполнение ↔ дорожка» даёт 2.07:1 — выше палитрой владельца не поднять, поэтому выбрана та пара, где обе половины читаются на самом фоне |
| 8.3 сирота в «Замечаниях» | гард поднят в `open`/`pin` самого экрана (одно место вместо двух у зовущих), сирота помечается и когда раздел НАЗВАН, но отсутствует в списке |
| 8.4 съёмка | (а) флаг не пишется, пока не полетел первый запрос, и защёлка ждёт 150 мс тишины — **замер показал дефект хуже описанного:** `/scale` снимался со строкой «загрузка разделов…», потому что между волнами чтений счётчик честно падает в ноль; (б) `shot.mjs` и `scenes.mjs` ждут доигрывания анимаций перед axe |
| 8.5 минорные | кэш канвас-замера запоминает ширину только если шрифт реально доступен (`document.fonts.check`); пин вкладки — только левая кнопка и выделение ВНУТРИ этой главы; `termStatus` больше не носит нерендерящихся слов; комментарии токенов исправлены числами (3.58:1), `--color-note` поднят до 3.07:1, `.paused` перестал быть no-op, `.offline` снят; сторож обрезки вкладок падает, если заголовок перестал быть `span`; PIL запинен |
| 8.5 ре-рендер экрана | **замер до/после:** флаг съёмки переехал в лист (`<ScreenshotFlag/>`), потому что `useIsFetching` перерисовывал ВЕСЬ экран на каждый старт и финиш запроса. Открытие 12 глав на `/scale`: p90 кадра 133 → 50‥67 мс, длинных кадров 16‥19 → 7‥13, длинных задач 22 (≈2080 мс) → 16 (≈1110 мс) |
| 8.6 доки | `FRONTEND_PLAN.md` §5.6 поправлен (модель «вырез в хроме» описана как СНЯТАЯ, в коде пилюля), §4 — сценариев девять, команда замера через venv; `README.md` — карта сессий и раздел про язык кода; `BACKLOG.md` Ф-47 — счёт костылей исправлен |
#### 3. Что нашла проверка исполнением, а не рассуждение
- **Каталог печатал `показано {shown} из {total}` буквально.** `@internationalized/string` подставляет
переменные ТОЛЬКО в скомпилированные функции (прочитано в исходнике библиотеки), а плоскую строку
отдаёт как есть; ICU-компилятор — это отдельный шаг сборки, от которого стек отказался, когда
взвешивал lingui. Подстановка `{name}` теперь наша, четыре строки, и на неё стоит тест; поймал
дефект сценарий `bank`, юнит-батарея его не видела.
- **Гейт строк сначала был написан по алфавиту** — и это было хуже, чем кажется: одно правило жило
в двух носителях (селектор ESLint и регексп теста), а перечень букв `ПТ|Ф|В|К|Д` был заплаткой под
конкретные строки бэклога. Переделано: ESLint ловит текст МЕСТОМ (буква в `JSXText` или в читаемом
атрибуте) — ловит и русский, и английский литерал, то есть строго сильнее; алфавит остался ровно
в одном месте и для ДРУГОГО правила («код зоны английский»), где комментарии иначе не проверить.
- **`/scale` снимался недоделанным** (см. 8.4а) — нашлось при первой же проверке нового флага кадром.
#### 4. Как шла работа
Свод языка и переезд строк — двенадцать параллельных агентов по непересекающимся файлам, каждый
вернул свои ключи структурой, каталог собран одним местом. Их находки, которые я разобрал руками:
JSDoc `look` у кнопки описывал три значения из четырёх (дописано), комментарий подвала панели
ссылался на токен, который стоит не в этом правиле (переписан по коду), комментарий панели цитировал
замер Fleet рядом с нашим изменившимся токеном (разведено явно). Ни одного комментария, оказавшегося
ВРАНЬЁМ против кода, свод не нашёл.
#### 5. Красный гейт, который я НЕ подогнал
Сцена `perf` на загруженной машине (в тот момент шло адверсариальное ревью двенадцатью агентами)
показала отклик поля 63‥79 мс при пороге 60 и уронила `check:full`. Порог не трогал — вместо этого
поставил A/B тем же зондом по двум сборкам подряд, чтобы нагрузка била в обе одинаково:
| Сборка | Отклик на символ, пять прогонов |
|---|---|
| до этой сессии (`git archive HEAD`) | 44 · 47 · 50 · 54 · 59 и 42 · 43 · 44 · 46 · 48 |
| эта сессия | 39 · 41 · 43 · 44 · 47 и 39 · 41 · 42 · 44 · 47 |
То есть регрессии нет — сборка стала БЫСТРЕЕ, а красный был машиной: сам замер сцены (три символа
через playwright с обратной дорогой) чувствительнее к нагрузке, чем зонд. На тихой машине сцена
даёт 43‥49 мс и проходит. Что с этим делать дальше — вопрос не подгонки порога, а устойчивости
замера; строку заводить не стал, потому что чинить пока нечего: гейт ловит то, ради чего заведён.
#### 6. Гейты на сдаче
`npm run check` — зелёный, **266 тестов** (было 160). `npm run check:full` — 7 маршрутов,
**9 сценариев**, ноль блокирующих нарушений axe (включая три зум-шага), драг панели p90 17 мс,
1 длинный кадр из 81. Оба новых гейта проверены живым нарушением: ESLint ловит `title="Настройки"`
И `title="Settings"`; сторож языка ловит русский комментарий в `api/revision.ts`.
### 10.08 — приёмка S3.6 оркестратором: ПРИНЯТО и залендено; поправки к записи S3.6 ### 10.08 — приёмка S3.6 оркестратором: ПРИНЯТО и залендено; поправки к записи S3.6
Гейты пере-прогнаны исполнением: `npm run check:full` EXIT=0, vitest **160**, `npm run shot` ×3, Гейты пере-прогнаны исполнением: `npm run check:full` EXIT=0, vitest **160**, `npm run shot` ×3,