textmachine/frontend/docs/frontend-PROGRESS.md

492 lines
87 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Журнал зоны «Фронт»
> **Файл переименован 04.08 по слову владельца: был `PROGRESS.md`, стал `frontend-PROGRESS.md`.**
> Причина — путаница с `docs/PROGRESS.md` оркестратора: два файла с одним именем в одном
> дереве, и ссылка «PROGRESS.md» без пути читалась по-разному в разных доках.
>
> **Оркестратору:** прогресс фронта пишется СЮДА же, в этот файл, а не в `docs/PROGRESS.md` —
> так у зоны один журнал и конфликтов правок в общем файле не возникает (слово владельца 04.08).
>
> Зонный журнал: сессии фронта пишут сюда сами и работают независимо (решение владельца 02.08).
> Хвосты — `BACKLOG.md`, план и замеры — `FRONTEND_PLAN.md`, ратифицированные пины —
> `STACK_DECISIONS.md`, контракт API — спека `api-contract/openapi.yaml` и спутник
> `API_CONTRACT_DRAFT.md` (`API_CONTRACT_INPUT.md` — исполненный вход, под ⚠-баннером).
> Сверху — текущее состояние, ниже — хроника по сессиям.
## Текущее состояние
> **Запись оркестратора №15, 07.08.** Абзацы ниже — состояние на 04.08, и первый из них с тех пор
> УСТАРЕЛ: «замок на входе закрыт, контракта API v0 нет» больше не так. Контракт ратифицирован
> **D39.99**, канон — `docs/architecture/14-api-contract/` (спека + компаньон-README), зонная копия
> `api-contract/openapi.yaml` — байт-зеркало канона. Вторая сторона контракта, платформа, **написана,
> принята и залендена** (D39.109): вход через OIDC, сессии, кредитный леджер, админ-CLI. Строка 95
> единого бэклога закрыта.
>
> **S3 ИСПОЛНЕН и ПРИНЯТ D39.115** (`60595f6`); промт отработан и заархивирован. Было в этой строке до 08.08: «запускается по слову владельца, промт готов» (`S3_SESSION_PROMPT.md`) и с 07.08 несёт три
> новых пункта списка правок спеки: **А-нуль** — шапка `info` спеки исправлена мной (три дня она
> называла себя нератифицированным черновиком S3 и ссылалась на несуществующий рядом компаньон;
> S3 остаётся бампнуть `version`) · **В-трис** — управляемый потолок прогона, решение владельца
> 07.08 (шкала в ИНТЕРФЕЙСЕ от минимума до доступного остатка, единица — ГЛАВЫ, не доллары, иначе
> это амендмент D39.84; максимум = баланс минус открытые холды ⚠ ФОРМУЛА ОШИБОЧНА, superseded D39.115 п.2(а): максимум = Balance КАК ЕСТЬ, холд уже дебет (вычитание дважды резало шкалу; испр. D39.125); носитель пересчёта «главы → деньги»
> — платформа, ручка объявляется правкой спеки) · **В-кватер** — фронт живёт на ТОМ ЖЕ origin, что
> платформа: CORS-слоя в ней нет вовсе, preflight `OPTIONS` с чужим `Origin` получает 401 от гарда
> сессии (замер на живом бинаре, PD-96 регистра платформы) ⇒ в деве ходить через прокси
> dev-сервера, кросс-origin не проектировать.
>
> **Мелочь зоны, которую стоит закрыть при следующем касании:** `API_CONTRACT_DRAFT.md` — второй
> экземпляр компаньона; канон компаньона теперь `docs/architecture/14-api-contract/README.md`,
> поэтому зонному файлу нужен баннер-указатель, иначе это второй носитель одного состояния.
> **Запись оркестратора №15, 08.08 (после приёмки S3) — СЛОВО ВЛАДЕЛЬЦА О КАЧЕСТВЕ, гейт на S4.**
> Владельцу НЕ нравится текущее качество фронта; названная претензия — «логика спама вкладками»:
> вкладки обязаны работать **ровно как в VS Code** — одиночный клик открывает PREVIEW-вкладку,
> следующий одиночный клик ЗАМЕЩАЕТ её содержимое (новая вкладка не плодится), пин вкладки — по
> двойному клику/взаимодействию с содержимым. Полный список претензий владелец сформулирует
> отдельным входом — этот абзац лишь первый пункт, НЕ весь список. **Диспозиция оркестратора:**
> S4 НЕ стартует до списка; когда список придёт — сначала «S3.5 фикс-пак оболочки» (вкладки
> по VS Code-модели + Ф-19 прокрутка + список владельца), затем S4 на починенной оболочке.
> Промт S3.5 выдаёт оркестратор по слову владельца.
> **Запись оркестратора №16, 09.08 — список владельца ПРИШЁЛ, промт S3.5 ВЫДАН.** Абзац выше
> исполнен: полный список претензий (24 замечания, снятые владельцем с живого прогона витрины)
> получен 09.08 и завёрнут в промт **`S35_SESSION_PROMPT.md`** (эта папка): VS Code-модель
> вкладок + Ф-19 + все 24 номера блоками, приёмка кадрами ДО/ПОСЛЕ и playwright-сценариями,
> референс драг-ручки — vojo (`src/app/components/page/Page.tsx:191-300`, `style.css.ts:11-70`).
> Запуск сессии — по слову владельца; S4 остаётся гейчен до приёмки S3.5. Попутное: замечание
> (10) владельца независимо подтвердило Ф-21 — полоска замечания нечитаема без слова; само
> слово ступени — по-прежнему В-3 на владельце. Референс `antigravity_add_folder.png` докинут
> владельцем 09.08 (модал добавления книги, замечание (12)).
> **Запись фронт-сессии S3, 08.08.** Абзац «S3 НЕ сделана: замок закрыт» ниже — состояние на
> 04.08, и он УСТАРЕЛ целиком: замок открыт, **S3 сделана**. Хроника — первым разделом ниже.
> Коротко: `src/api/` асинхронен и разговаривает HTTP; MSW стоит СЕТЕВЫМ моком, поэтому приложение
> делает настоящий `fetch` и настоящий `EventSource`; фикстур шесть миров, по маршруту на каждый;
> живой прогресс идёт по SSE и двигает счётчик в браузере (замерено, не предположено); `types.ts`
> удалён, экраны живут на типах контракта; ветка неизвестного значения стоит на шве. Спека
> бампнута до **0.2.0** со всем списком правок промта — канон правит оркестратор по
> канон `docs/architecture/14-api-contract/` (патч ПРИМЕНЁН и удалён, D39.115). Ф-15 и Ф-22 закрыты, заведены Ф-26..Ф-31.
> `npm run check` — 7 шагов, **108 тестов** на 08.08 (число живёт в батарее, а не здесь: сверяется прогоном), зелёный; `npm run shot` — шесть маршрутов, гейт
> доступности зелёный на всех.
> **Запись фронт-сессии S3.5, 09.08.** Фикс-пак оболочки по 24 замечаниям владельца ИСПОЛНЕН —
> прогон по всем номерам первым разделом хроники ниже. Коротко: вкладки живут по модели VS Code
> (предпросмотр/закрепление), Ф-19 закрыта keep-alive панелей, полоска ресайза больше не залипает
> (причина найдена в коде библиотеки), настройки и добавление книги открываются модальными окнами,
> лупа стала палитрой быстрого перехода, банк перепридуман со спойлерами по окну применимости,
> кнопка-заглушка «Подписать банк» снята в пользу честного состояния, палитра ушла в тёплый подтон
> (три варианта кадрами), причина «шакальных» иконок найдена в сетке набора и вылечена. Гейты
> зелёные, **контраст axe — ноль узлов на всех семи маршрутах** (Ф-11 закрыта замером).
> Адверсариальное ревью тремя линзами исполнено, находки и диспозиции — там же; две из них были
> моими дефектами по существу (правка полос увела ОТ референса; тронуто слово паузы, закреплённое
> за владельцем) и откачены.
> Ждут владельца: В-7 (масштаб интерфейса), В-8 (слово состояния в дереве), Ф-38 (защита вкладки
> «Замечания»), выбор палитры. Ждёт оркестратора: два черновика правки спеки — поля банка и
> `BookIntake.title` (в конце записи S3.5).
> **Запись фронт-сессии S3.6, 10.08.** Второй круг замечаний владельца (10 пунктов, снятых
> с прогона после S3.5) отработан. Коротко: палитра переведена на НЕЙТРАЛЬНЫЙ ряд, снятый
> замером с `fleet_2.png` и `antigravity_*.png` (тёплый подтон S3.5 был моей отсебятиной
> ПРОТИВ этих же референсов); вкладки перестроены по замеру fleet_2 — полоса вкладок это ХРОМ,
> активная вкладка вырезана из него цветом полотна; найдена и починена причина обрезки коротких
> названий; ручка ресайза перенесена из vojo дословно, включая числа упоров; линия жёлоба
> читалки — в цвет оболочки, ширина набора отпущена по окну; **банк памяти переделан в таблицу**
> и открывается вкладкой в центре, спойлер снят с ПЕРЕВОДА и поставлен на описание; иконки книги
> и главы разведены и несут состояние цветом. Первым разделом записи — АУДИТ всех 24 буллетов
> S3.5 по коду (просьба владельца), с честными вердиктами второго круга.
> Ждут не меня: две дыры платформы/контракта под банк (ниже, «Жалобы») и подписной механизм S5.
> **Сессия S3.6 ЗАКРЫТА 10.08 (разделы 1215 хроники).** Дерево готово к лендингу, фронт не
> коммитит. Гейты: `npm run check:full` зелёный — 160 тестов, 7 маршрутов, 7 сценариев, ноль
> блокирующих нарушений axe, драг панели p90 17 мс. Новые строки бэклога Ф-49…Ф-51 (свежесть
> текста главы · потерянные кадры потока · resync сбрасывает один гард из двух) заведены по
> ресёрчу отдельным агентом и проверены по коду; два моих собственных предложения тот же ресёрч
> опроверг, и это записано в разделе 15 вместе с долгами сессии.
> **Запись оркестратора, 14.08 — ГЕЙТ S4 ПАЛ (платформа P5 принята, D39.130): живой `POST /books`
> существует; S4-промт выдаёт оркестратор по слову владельца** (вход: экраны библиотеки/загрузки +
> находки приёмки S3.7 + спек-правка 0.2.3). Попутно аудит-свип корпуса 14.08 — стейлы зонных доков,
> закрыть S4-сессией (или раньше): `FRONTEND_PLAN.md:42-43` «платформа = ноль строк кода» и `: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 принята. Два числа живут в двух
> версиях без арбитража: ключей i18n — 147 (запись S3.7 ниже) против 157 (Ф-35 и живой `ru.ts`;
> верно **157**) · цена бандла +7999 (запись) против +6971 (Ф-35). Долги без Ф-строки: RTL-проверка
> (триггер «появление I18nProvider» НАСТУПИЛ в S3.7) · спойлер достаётся поиском по странице/печатью
> в PDF (продуктовое слово) · канвас-замер не знает `lang` при двух CJK-лицах — завести Ф-строки
> S4-сессией. Промты S3/S3.5/S3.7 архивированы с баннерами-исходами (`docs/archive/prompts/FRONTEND_S3*`),
> зонные копии сняты.
>
> **Дописка 14.08 (вечер): S4-промт ВЫДАН** — `S4_SESSION_PROMPT.md` (эта папка), запуск одобрен
> владельцем. Его решения того же дня, внесённые в промт: (1) `BookIntake.title` — в спек-правку
> 0.2.3 (ратификация оркестратора как исполнение замечания 12 S3.5, владелец подтвердил);
> (2) продуктовые фразы причин отказа PD-173 пишет S4-сессия сама — по реальному флоу отказов
> платформы, в границах ПТ-33, на утверждение владельцем по отчёту; (3) Ф-52 — `--color-danger`
> осветлить на ступень до ≥3:1 силами S4 (закрыть замером).
> **Запись фронт-сессии S4, 14.08.** Путь «у меня есть файл → книга переводится» построен и прожит
> в мире моков: форма загрузки отправляет книгу (XHR — `fetch` прогресса ТЕЛА запроса не даёт вовсе),
> 201 приносит `parsing`, разбор — отдельный видимый шаг БЕЗ выдуманного процента, отказы интейка
> (400/404/408/413) и отказ книги (три причины PD-173 с разными советами) — состояния формы и
> карточки, а не алерты. Форма запуска даёт потолок в ГЛАВАХ из `CeilingBounds`; потолочный стоп
> прожит по контракту (`EventCeiling` + `paused`), и оповещение — не тост, а несъезжающая фраза в
> статус-полосе и на карточке (аргумент в записи). Библиотека: дерево свыше 200 разделов
> складывается по сотням, книга в дереве стала ВЫБИРАЕМОЙ (без этого половина статусов была
> недостижима на карточке), все одиннадцать состояний прожиты. Контракт зонной копии бампнут до
> **0.2.3** (PD-172/173/174/180 + `BookIntake.title`); ⚠ по коду платформы `not_configured` на
> отклонённую книгу сегодня не попадает вовсе — названо в записи. Девять несущих находок приёмки
> S3.7 разобраны, и одна из них ОПРОВЕРГЛА клейм S3.7 замером (resync рвал живой поток, когда
> чтение медленное).
>
> ⚠ **Три ошибки в самом промте S4, найденные вторым проходом ревью и исправленные** (промт писала
> нейросеть, и это ровно тот случай): (1) «поле после файла = 400» — платформа так НЕ делает, она
> перестаёт читать на файле, и необязательное поле за ним просто теряется (спека и фикстура
> исправлены, два теста); (2) §7 велит записать «7 шагов у `npm run check`» — их шесть, и первая
> редакция моей правки повторила ошибку промта; (3) §4 сводит 409 на старте к «уехал потолок», а
> платформа отвечает им на пять разных состояний — совет на экране сделан причинно-нейтральным.
> Ждут владельца: **В-10** (спойлер — защита или вежливость) и **В-11** (фразы отказа PD-173 на
> утверждение).
> **Запись фронт-сессии 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 — ПРИЁМКА S3.7: принято и залендено (D39.129).** Гейты
> пере-прогнаны исполнением (279 тестов, 9 сценариев, EXIT=0); **арбитраж по 8.1 — права
> СЕССИЯ, HIGH приёмки S3.6 снята как моя ложноположительная** (разбор — приёмочной записью
> хроники). 12 находок ревью (1 high: ложный клейм про импорт `fill.ts` сценами) — носитель:
> блок находок следующего фронт-промта (S4). Канон контракта догнал 0.2.2 диффом при лендинге,
> зеркало байт-равно. **S4 — следующий этап; промт выдаёт оркестратор** (после приёмки
> платформы P5 — экран загрузки стоит на её `POST /books`).
> **Четвёртый круг замечаний, 10.08 (раздел 12 хроники).** Четыре бага владельца по таблице банка
> закрыты, и один из них был МОЙ механизм: заморозка ширин (`useSettledWidth`) оставляла таблицу
> сжатой после драга, а перезамер показал, что она ничего не покупала — драг держит p90 17 мс и
> без неё. Ширины отданы алгоритму библиотеки, содержимое меряется канвасом по всему банку и идёт
> ПОТОЛКОМ столбца. Спойлер описания переделан с фильтра на боксе на размытие глифов. Сверх списка
> владельца найдено шесть дефектов того же класса — в том числе замер по запасному шрифту (4.7%
> ширины) и живой `getComputedStyle`, обнулявшийся за время загрузки шрифтов. Приёмка: 158 тестов,
> 7 сценариев, 4 новые проверки, каждая падает на откате своего фикса.
> **Запись оркестратора, 10.08 — ПРИЁМКА S3.6: принято и залендено (D39.127).** Гейты
> пере-прогнаны исполнением, 12 находок ревью (1 high) и поправки к записи S3.6 — первой записью
> хроники ниже. Промт **S3.7** выдан (`S37_SESSION_PROMPT.md`: Ф-49…Ф-51, Ф-47 ратифицирован,
> Ф-40, Ф-25, Ф-35 — словарь строк + гейт против хардкода русского; ⚠ Ф-35 в первой редакции
> промта отсутствовала — пропуск поймал владелец при ревью промта, D39.127 п.2г), запуск
> по слову владельца; **S4 — после приёмки S3.7.** Экспорт банка заведён строкой 169
> единого бэклога (Ф-43).
- **Пройдено:** S0 (план), S1 (инструменты, скриншот-цикл, `tokens.css`, витрина),
S2 (оболочка трёх панелей, слой `src/ui/`, масштаб списков, хвосты гейтов),
S3 (слой данных: контракт 0.2.0, MSW, фикстуры всех состояний, живой поток, типы контракта),
S3.5 (фикс-пак оболочки: 24 замечания владельца, сценарии интеракций, пере-замер полос),
**S3.6 (второй круг: палитра по замеру референсов, модель вкладок fleet_2, банк таблицей,
ручка из vojo дословно)**, **S3.7 (долги слоя данных: контракт 0.2.2, каталог i18n 157 ключей,
код зоны на английском; D39.129)**, **S4 (загрузка книги и запуск прогона на контракте 0.2.3,
библиотека на масштабе, находки приёмки S3.7 — ждёт приёмки)**.
-**АБЗАЦ НИЖЕ ИСТОРИЧЕСКИЙ (04.08), читать как хронику:** замок с тех пор открыт (контракт ратифицирован D39.99), S3 исполнен и принят D39.115. Оставлен, потому что объясняет, ПОЧЕМУ S3 однажды остановилась, а не как диспозиция.
- **S3 НЕ сделана: замок на входе закрыт, проверено исполнением 04.08.** Контракта API v0
по-прежнему нет (`docs/architecture/14-api-contract.md` отсутствует; строка 95 единого
бэклога — статус «дизайн-промт по слову владельца», то есть не исполнена). Вместо S3 сессия
сделала то, что предписывает её же промт на этот случай: **довела Ф-14 до артефакта
`API_CONTRACT_INPUT.md`** и остановилась. Кода не написано ни строки — это диспозиция,
а не недоделка: моки, снятые не с того контракта, разойдутся с API, ровно ради чего
строка 95 и заведена.
- **Написан черновик контракта, принят в работу ревью оркестратора и ДОФИКШЕН (04.08).**
Форма сменена решением владельца: нормативная поверхность — **OpenAPI 3.1
`docs/api-contract/openapi.yaml`**, `API_CONTRACT_DRAFT.md` стал обязательным спутником
(провенанс ✓/◆/○, обоснования, К-вопросы — то, чего YAML не выражает). Дом ратифицированной
копии — `docs/architecture/14-api-contract/`, зона оркестратора; после ратификации типы
генерятся из перенесённой копии — контракт первичен.
- **Гейт контракта живой:** `npm run check` стал шестишаговым (spectral на строгом пороге),
`openapi-typescript` генерит `src/api/schema.ts`, тест дрифта не даёт спеке и типам
разъехаться, ветка неизвестного значения стоит на шве (`src/api/contract.ts`), MSW отдаёт
тело в форме контракта. Четыре формы нарушения проверены живьём (`FRONTEND_PLAN.md` §5.4.2).
- **Ждёт оркестратора, четыре вещи:** (1) ратифицировать спеку и перенести в
`docs/architecture/14-api-contract/`, либо вернуть с правками; (2) три зависимости, которых
фронт заводить не может — **артефакт экспорта БАНКА** (строки в едином бэклоге нет вовсе:
101 даёт таблицу подписи, не банк), **механизм поднятия потолка** (без него `resume` после
стопа по потолку прогон не двигает) и правка устаревшего комментария провенанса
`store/migrate.go:193`; (3) залендить дерево сессии; (4) вопросы владельцу — В-4, В-5 ниже
и К-1..К-12 спутника, из них продуктовых пять, остальные — автору контракта и платформе.
- **Ждёт владельца:** контраст палитры (`BACKLOG.md` Ф-11) и два вопроса ниже — В-1 диск,
В-2 копирайт.
- **Ждёт движка:** манифест глав и пофазный прогресс (единый бэклог, строки 99100),
к S5 — машиночитаемая таблица подписи банка (строка 101).
- `npm run check` зелёный (6 шагов, 80 тестов), `npm run check:full` зелёный, гейт доступности
зелёный на обоих маршрутах. Гейтов стало больше: включён Ф-4 (отступы), закрыты Ф-9 и Ф-10,
по ревью оркестратора 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`.
## Решения владельца по продукту
Записываю здесь, потому что они меняют раскладку из §2 промта, а промт правит не фронт-сессия.
### 04.08 — где стоит «+» в рядах вкладок (закрывает половину Ф-7)
Вопрос был поставлен так: промт требует «+» **вместе с действием**, которое он запускает, а наборы
вкладок у нас фиксированные (слева `Книги · Поиск`, справа `О книге · Замечания · Банк`) —
пользователь их не расширяет, и fleet-овский смысл «+» («добавить инструмент») к ним не применим.
Владелец: **«+» слева = «Добавить книгу»**. Отсюда:
| Было | Стало | Почему |
|---|---|---|
| «+ Добавить книгу» строкой в дереве, «+» в рядах вкладок нет | «+» в ряду вкладок ЛЕВОЙ панели, строка из дерева убрана | одна вещь — одно место; в референсе «+» стоит ровно там |
| — | в центре и справа «+» нет | добавлять в фиксированный набор нечего, кнопка вышла бы декоративной |
В S2 действие открывает вкладку-документ «Добавить книгу»; содержимое экрана (§3.1) делает S4.
### 04.08 — референсы вернулись на диск
`frontend/references/*.png` в `.gitignore` и в git никогда не заезжали, поэтому в третьей сессии
их на диске не оказалось вовсе. Владелец положил файлы обратно. **Следствие для будущих сессий:
не считать наличие референсов данностью — если папки нет, это не «их отменили», а спросить.**
### 02.08 — раскладка: банк памяти переезжает в правую панель
Владелец, глядя на витрину: **«банк памяти перенёс бы в правую вкладку, чтоб можно было
параллельно вертикально смотреть и оригинал, и главу, и банк памяти, а не горизонтально»**.
Плюс три дефекта структуры в той же реплике: две кнопки настроек, банк продублирован
(вкладка слева + отдельная карточка внизу), окно главы слишком мало.
Что из этого следует и сделано:
| Было | Стало | Почему |
|---|---|---|
| Настройки в верхней полосе И внизу левой панели | только внизу левой панели | промт §3.12: настройки — отдельный раздел из низа левой панели, второй вход лишний |
| Банк во вкладке слева И карточкой в центре снизу | одна вкладка в правой панели | одна вещь — одно место; слева осталась только навигация |
| Центр разрезан на две карточки | одна панель во всю высоту | нижняя карточка была скопирована с терминала Fleet и не несла задачи |
| Кнопки сворачивания трёх панелей | двух | кнопка есть у той панели, которая существует |
**Вертикальный параллелизм — суть решения:** рабочий цикл читателя это «читаю перевод → спотыкаюсь
о термин → проверяю его в банке». Все три вещи обязаны быть видны одновременно, поэтому колонки:
навигация · оригинал+перевод · справочное о читаемой главе. Правая панель становится панелью
контекста, и её вкладки — `О книге · Замечания · Банк`.
**Что при этом надо развести (иначе §3.5 ломается):** у банка две разные работы.
Справочная — «что это за термин», ей хватает 320px правой панели. Подписная — сотни терминов
подряд, клавиатура важнее мыши, массовые действия — в 320px не помещается. Поэтому подписной
экран открывается **вкладкой в центре**, как документ, а правая панель ведёт в него действием
«Подписать банк». В витрине эта связка показана.
### 02.08 — данные: моки берут форму от движка
Владелец: **«всё на диске лежит, и главы, и банки памяти»**. Разбор бэкенда подтвердил: моя
первая фикстура выдумывала поля (`kind: 'имя'`, `state: 'подписан'`), а промт прямо запрещает
изобретать API. Формы переписаны по настоящим:
- банк — таблица `glossary` (`backend/internal/store/migrate.go:176`): `src · dst · type · sense ·
status · source · since_ch/until_ch`. Статусы подписи ровно три: `auto|draft|approved`,
провенанс — `seed|ruby|mined` (⚠ **испр. 04.08 по ревью оркестратора:** здесь стояло
`seed|ruby|auto` плюс `mined` по комментарию схемы; комментарий устарел, а литералы `"auto"`
в коде пишут СТАТУС, не провенанс — `membank/memseed.go:328`).
**Типы — исправлено 04.08 по ревью оркестратора:** сама колонка `type` в схеме свободный текст,
и её комментарий перечень не закрывает («name|term|title|…»), поэтому истина — гейты в Go:
классификатор знает четыре (`terminology/classify.go:15`), банкнота принимает их же плюс
`nickname` (`pipeline/banknote.go:74`). Итого пять: `name|place|title|term|nickname`.
`org` и `fullname` движок не знает вовсе — они приехали в тип фронта из этой самой строки;
- пары — `ChunkExport` из `tmctl export --pairs` (`backend/internal/pipeline/export.go:25`):
`chapter · chunk_idx · disposition · flag_reason · detail · final_text · source`;
- причины замечаний — enum из `backend/internal/pipeline/disposition.go:56-104`.
**Следствие для интерфейса, которое из этого выросло:** движок говорит своим языком —
`sanitizer_stripped`, «CJK leak in the ru output: 第一节». Промт §4.1 запрещает показывать это
пользователю. Значит между движком и экраном обязан стоять **слой перевода вердиктов
в продуктовые понятия**, и он заведён одной картой в данных: причина → человеческая фраза;
поле `detail` не показывается никогда. Это же ПТ-33 реестра требований.
### 02.08 — шов данных заведён: моки выкидываются одной папкой
Владелец: **«все моки рано или поздно придётся выкинуть; нужна минимальность моков,
минимальная инвазивность в код и изолированность»**. На вопрос «соблюдаешь ли» честный ответ
был «нет»: правило «данные только через `src/api/`» стояло в плане, а в коде компонент
импортировал фикстуру напрямую — шва не было вовсе. Радиус поражения был мал (один экран),
но образец для S2S7 задавался неправильный.
Заведено: `src/api/` — типы и функции, единственный вход; `src/mock/` — фикстура, которую
видит только `api/`. Правило теперь машинное, а не на совести ревьюера: `no-restricted-imports`
на `**/mock/**` и запрет сетевых вызовов, с исключением для `src/api/**`.
**Две поправки к этой записи, обе от ревью 02.08 (№3) — исходные формулировки были сильнее
сделанного:**
- «Доменных значений в разметке не осталось» — **было неверно**: в JSX оставались четыре
литерала языка (`lang="zh"`, `lang="ru"`, подпись пары `zh → ru`), и тот же проход,
который вынес числа в `book.*`, прошёл мимо них в той же строке. Починено: язык — код
в данных, имя считается `Intl.DisplayNames`, `lang` берётся из книги; правило закрыто
тестом (`src/generality.test.ts`), а не обещанием.
- «В день HTTP правится тело функций, экраны не трогаются» — **переобещание**. Верно только
про день замены MSW настоящим сервером. Асинхронность приезжает раньше, на S3, вместе
с MSW и TanStack Query — то есть ДО первого продуктового экрана (S4S7), поэтому
переписывать экраны и правда не придётся. Но четыре вызова витрины на S3 изменятся.
### 02.08 — что дал разбор канона: фронт мокает не тот контракт
`docs/README.md` прямо требует читать `research/23` перед любым кодом стыка. Не читал,
и это стоило двух вещей.
1. **D39.85 (`research/23` §0): фронт читает ТОЛЬКО read-модель платформы в Postgres,
материализованную из NDJSON-потока событий; движок не опрашивается никогда, чтение живого
SQLite движка — запрещённый анти-паттерн.** Значит формы `glossary`/`ChunkExport` — словарь
предметной области, но НЕ форма API. Типы фронта переписаны так, чтобы это было видно:
`src/api/types.ts` объявлен рабочей гипотезой до появления контракта.
2. **Единый бэклог, строка 95:** «Контракт API v0 + продуктовый словарь статусов, ранняя
вставка, зафиксировать артефактом ДО большого кода обеих сторон — фронт пишется на моках,
без пришпиленного контракта моки и API разойдутся». Дом — `docs/architecture/14-api-contract.md`,
**файла нет**. То есть фронт делает ровно то, ради предотвращения чего строка заведена.
Для S2 (оболочка, `src/ui/`) это не помеха. **Для S3 (слой данных) — вход, которого нет.**
### 02.08 — инверсия смысла двух вердиктов (дефект, внесённый фронтом)
Продуктовые фразы к замечаниям были написаны по ИМЕНИ причины, а не по её доккомменту,
и две из пяти получились наоборот:
- `glossary_miss` — «Термин не подписан в банке» ⟶ **неверно**. `disposition.go:78-85`:
«an **approved** term's src fired in the chunk but no accepted dst form appears in the
output — the model ignored the glossary». Термин подписан, его проигнорировал перевод.
Фраза посылала человека подписывать уже подписанное — по банку, который в каноне
центральная ценность.
- `sanitizer_stripped` — «Часть блока не переведена» ⟶ **неверно**. `disposition.go:96-104`:
«the chunk is NOT lost — the cleaned text is committed as the export»; `status.go:165-170`:
«the **least alarming** flag». Самый безобидный флаг из восьми подан как потеря текста.
Заодно вскрылось, что у движка есть **ратифицированная лестница важности вердиктов**
(`status.go:150-175`, ранги 1..8), а интерфейс красил все замечания одинаково — то есть
терял единственный сигнал приоритета. Введены две ступени: `attention` и `glance`.
**Правило на будущее:** фраза к вердикту пишется по доккомменту `disposition.go`, а не по имени
причины, и рядом кладётся цитата. Соответствие целиком — в шапке `src/mock/book.ts`; его
настоящий дом — контракт API (строка 95), не фронт.
### 02.08 — ревью №3 на полном каноне: что оно поменяло
Владелец разрешил читать весь корпус доков и потребовал прогнать ревью после чтения.
Прочитано: `CLAUDE.md` · `docs/README.md` · CURRENT-STATE и единый бэклог · `research/23` ·
`product-requirements.md` · карта D-лога. **Ответ на вопрос владельца о способе связи:
NDJSON — это шов ДВИЖОК↔ПЛАТФОРМА (D39.85), а фронту принадлежит JSON поверх HTTP плюс SSE
от платформы (D39.84). Разведено в `FRONTEND_PLAN.md` §0.2, потому что путал их я сам.**
Ревью: 5 линз × находки, на каждую независимый скептик с установкой опровергать.
15 находок → 12 проверено → **5 выжило, 7 опровергнуто**. Хардблокеров нет; S2 не блокирован ничем.
| Что | Диспозиция |
|---|---|
| Язык зашит в разметку (`lang="zh"`), а в типе — русское слово | починено: коды в данных + `Intl.DisplayNames` + тест-замок |
| Девять состояний нарисованы на ГЛАВАХ, хотя это состояния ПРОГОНА над книгой | починено: состояние → книга, у главы выполнение по юнитам; библиотека из нескольких книг |
| Прогресс — наивное «N из M глав», прямо запрещённое собственным планом | починено: две пары по юнитам, фикстура поставлена в середину черновой волны (наивный счётчик дал бы 0) |
| Сетевой гейт ловил только `fetch` — `EventSource` (ратифицированный транспорт) проходил молча | починено: восемь форм, все проверены живым нарушением |
| `npm run shot` зелен, когда экран не попал в список маршрутов скрипта | починено: тест сверяет `routes.tsx` и `shot.mjs` |
**Опровергнуто (и это ценнее половины находок):** гипотеза «синхронный `src/api/` — хардблокер,
нужен свой хук уже сегодня». Два независимых скептика показали, что S2 данных не читает вовсе,
а асинхронность приезжает на S3 вместе с MSW и TanStack Query — то есть самодельный хук был бы
работой S3, которую S3 же и выбросит. Правку я не делал; переобещание в журнале поправил.
**Что нашла не ревьюшница, а снимок:** после переноса состояний на книгу три пары из девяти
рисовались одинаково (готова ≡ не начата, перевод ≡ финал, ошибка ≡ не разобрана) — точка
не различает девять значений. Метка стала словом; цвет остался вторым каналом и живёт
на точке, а не на тексте (цвета замечания и отказа не проходят порог контраста для текста —
проверено axe: было 5 узлов, стало 14, вернулось к 5).
**⛔ ПИНГ ОРКЕСТРАТОРА №19 — 23.08, при разморозке зоны (сейчас действий не требует).**
Аудит доков нашёл два расхождения внутри зоны; рукой не лезу, зона заморожена.
1. **Три из одиннадцати вопросов ниже уже ОТВЕЧЕНЫ каноном** и просто не погашены — при разморозке
сверить каждый против D-лога прежде, чем нести владельцу повторно.
2а. **Ключ `prepare` вашего `package.json` — единственный бутстрап РЕПО-ШИРОКОГО гейта доков (дописано 24.08, строка 220).**
`frontend/scripts/githooks/install.mjs` — единственный в дереве установщик диспетчера `.git/hooks/pre-commit`, а тот
судит `CLAUDE.md` и доки трёх зон, не только ваши. Следствие проверено исполнением: на свежем клоне без `npm install`
гейт молча выключен. Просьба при разморозке: перевести `prepare` на зоно-нейтральный установщик, который заведут в
`docs/scripts/githooks/`, чтобы единственным писателем диспетчера был он. Сам ваш ФРАГМЕНТ хука менять не надо.
2. **Пространство номеров «В-N» разъехалось** между этим журналом и `docs/research/28-contract-review.md`:
доклад ссылается на В-1/В-2/В-5/В-6/В-7 как на ДРУГИЕ вопросы, чем одноимённые строки здесь.
Пока номера двусмысленны, ссылка «см. В-6» указывает в два разных места.
## Открытые вопросы к владельцу
| # | Вопрос | Почему это его вопрос |
|---|---|---|
| В-1 | **Данные привязаны к одной машине.** Вся фактура — прогоны, экспорты, банки — лежит в `/home/ubuntu/books/gu-zhenren/` вне git; оба `backend/example/sample-*.db` пустые (только схема); пути стенда зашиты в тесты (`miner_parity_test.go:33-35`, `labelharness_test.go:43`) и в `book.yaml` абсолютными путями. Владелец сказал: «мне не нравится, что это живёт конкретно на моём диске». Лечение — платформа (`platform/README.md:20-29`: библиотека книг, хранение исходников и экспортов), но платформы ещё нет ни строки. Фронт от этого не зависит (работает на моках), но **вопрос на движок/платформу, а не на фронт** | скоуп-решение и порядок работ |
| В-3 | **Каким словом называть ступень замечания.** Сейчас `attention` и `glance` различаются только цветом полоски: синяя и серая. Зрячему разница читается ещё и светлотой, скринридеру — никак. Лечение то же, что уже применено к состоянию прогона книги: слово рядом с цветом. Но словарь замечаний продуктовый (ПТ-33), а §3.8 требует, чтобы экран не выглядел тревожным, — «важно / неважно» и «ошибка / предупреждение» не годятся. Строка Ф-21 | продуктовая формулировка, которую видит пользователь |
| В-6 | **Упёрся в свой потолок ≠ кончились деньги, а интерфейс их не различает.** Владелец 07.08 дал человеку поставить перед стартом колпак в ГЛАВАХ; платформа берёт холд на его сумму. Но машинная причина паузы в контракте ровно одна — `credit_exhausted`, и она про кредит. Значит прогон, честно доехавший до выбранной человеком границы, и прогон, у которого кончился баланс, приходят на экран одной фразой «перевод остановлен: лимиты исчерпаны». Первому она врёт: лимит не исчерпан, человек сам так решил, и следующее действие у него другое — поднять колпак, а не пополнить счёт. Нужно ли второе значение и какая у него фраза — продуктовое. Заведено К-13, строка Ф-31 | продуктовая формулировка, которую видит пользователь, и разное следующее действие |
| В-8 | **Какое слово о состоянии книги стоит в дереве.** Замечание 23 потребовало бейджу ФИКС-место, и оно сделано; но две метки словаря в него не помещаются и усекаются с тултипом — «остановлена: лимиты» (19 знаков) и ветка неизвестного «неизвестное состояние» (21). Укоротить их сессия НЕ вправе: фраза паузы зарезервирована за владельцем (В-6), и первый заход S3.5 её укоротил и был откачен собственным ревью. Варианты: (а) оставить усечение с тултипом, (б) владелец даёт короткое слово для дерева, а полная фраза остаётся в статус-полосе, (в) расширить колонку бейджа за счёт названия книги | продуктовая формулировка, которую видит пользователь |
| В-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`), и каркасный пункт настроек честно говорит «сейчас интерфейс только русский» | продуктовое решение и обещание пользователю |
| В-10 | **Спойлер банка — это защита или вежливость?** Замер S4: закрытое описание лежит в тексте страницы, `window.find()` его находит, то есть Ctrl+F подсвечивает закрытую ячейку; под `@media print` размытие сохраняется, но текстовый слой PDF строится из DOM. Если спойлер — ЗАЩИТА от спойлера сюжета, описание не должно приезжать в браузер до раскрытия, а это правка контракта (признак «показывать смыслы» на чтении банка). Если ВЕЖЛИВОСТЬ («не мозолит глаза, но достать можно») — сделанного достаточно, и цена названа. Строка Ф-59 | продуктовое решение и правка контракта |
| В-11 | **Фразы отказа книги (PD-173) — на утверждение.** Контракт 0.2.3 несёт машинную причину (`source_unreadable` · `not_configured` · `parser_unavailable`), а слова пишет клиент — их сочинила эта сессия по слову владельца 14.08 и они ждут его «да»: «Файл не удалось разобрать на разделы» / «Проверьте файл — возможно, это не текст книги — и добавьте её заново»; «Сервис пока не готов принять эту книгу» / «Файл здесь ни при чём: повторная загрузка поможет не раньше, чем мы это наладим»; «Не удалось обработать файл на нашей стороне» / «Файл здесь ни при чём: попробуйте добавить книгу позже»; неизвестная причина — «Книгу не удалось принять» / «Причина не названа. Попробуйте добавить книгу заново или позже» | продуктовая формулировка, которую видит пользователь |
| В-2 | **Авторское право на текст фикстур.** Витрина использует короткую выдержку из настоящего прогона (蛊真人). Правило проекта уже есть: `eval/.gitignore:4` держит копирайтные тексты вне git. Сейчас взят объём под проверку плотности и не больше; нужно ли убрать совсем и заменить синтетикой — решать владельцу | юридика |
| В-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 единого бэклога | продуктовое: обещание срока пользователю |
## Хроника
### 15.08 — приёмка S4 оркестратором №17: ПРИНЯТО и залендено (`267aa35`); контракт 0.2.3 в каноне (D39.135)
Панель 5 линз в изолированных копиях (слепой вердикт по заказу+диффу · охота вне карты · пере-ран гейтов · линза истинности спеки против кода платформы · кросс-модельный текст-аудит Opus). Пере-ран: `check` 335/335 · `check:full` EXIT=0 (8 маршрутов, 11 сценариев, axe 0 блокирующих) · spectral/типы/дрейф зелёные · до-пакные 157 ключей и чанк 724130 подтверждены обратным применением диффа байт-в-байт · живые нарушения гейтов — красные. Ратификации и confirm-лист владельцу — D39.135.
**Фикс-лист ФС (носитель состава — эта запись; вход промта S5):** ФС-1 (major, мир intake) прогон над загруженной книгой стартует с `begin(0)` — общий прогресс 0/0 весь прогон, ETA = NaN (лечение: begin суммой units_total глав); путь заказа §4 «книга из формы переводится» в мок-мире добить · ФС-2 showcase: принятый старт прогона не меняет мир — следующее чтение отдаёт прежнее состояние, «Перевести» выглядит как ничего · ФС-3 мир intake: повторный старт переиспользует id прогона — поток не переподписывается, translating вечно (verify_bank тем же кластером: наблюдаемого эффекта в моках нет, awaiting_bank недостижим) · ФС-4 `BookIntake.title` maxLength 200 не держит никто на клиенте (TextField без лимита — собственная спека нарушаема своим клиентом) · ФС-5 докблок `upload.ts` несёт СНЯТОЕ правило «field after file → 400» (неверно для необязательного) · ФС-6 два дока «spectral шестым шагом» (`STACK_DECISIONS.md:116`, `FRONTEND_PLAN.md:124`) — spectral четвёртый из шести · ФС-7 мок считает части формы по ВСЕЙ форме (платформа — до файла) и меряет 413 по file.size (платформа — по всему телу) — мок строже провода · ФС-8 флейк сцены refusals: closeModal не дождался закрытия за 5000 мс (1 из 3 на тихой машине) · ФС-9 `role="status"` оборачивает байтовый прогресс отправки — на живом XHR скринридер зачитывает каждое обновление (в регионе — только смены состояний) · ФС-10 группа из одного раздела подписывается «разделы 201201» · ФС-11 интейк-мир: ПЕРВОЕ нажатие «Перевести» всегда 409 (счётчик; кандидат — маркер) · ФС-12 после-пакные числа Ф-35 слегка отстают от дерева (пересборка: 800293 / 246670 gzip против записанных 800219 / 243446).
**Поправки к записи S4 (чужой текст не редактирую):** «словарь платформы — четыре значения» → в коде ПЯТЬ (пропущен `schema_mismatch`) · «одна из трёх фраз сегодня недостижима» → недостижимы ВСЕ ТРИ: платформа `reject_reason` вообще не проецирует (`v0.go:497` «never projected») — доезжает только ветка неизвестного · §1/§2 записи несут снятое правило PD-172 «поле после файла = 400», которое сама же §9а опровергла (код и спека исправлены, текст записи — нет) · «136 проверок» = 134 (наивный греп ловил 2 строки vite) · «31 строка DOM / 59 618px» — замер S2 04.08, не этого пака · «46 находок → 6 выжило» = 5 различных (одна — дубль) · три поправки к записи S3.7 из заказа §6: разобрана только цена бандла; «дрейф ширин hidden» и «счёт 106 из 119» остались на записи оркестратора 14.08 (носитель там, дефекта сессии нет — фиксирую для полноты).
*(Записи сессий S0S4 и их приёмок (0214.08) — в [archive/frontend-PROGRESS-S0-S4.md](archive/frontend-PROGRESS-S0-S4.md); вынесено 16.08 по слову владельца. Запись приёмки S4 с фикс-листом ФС — ВЫШЕ, она живая.)*
## Пинг оркестратора №15 (09.08): контракт 0.2.1 — `503` на старте прогона; платформа-раннер заленден
- **Контракт бампнут 0.2.0 → 0.2.1** (D39.123): `POST /books/{bookId}/runs` получил ответ **`503`**
(`ServiceUnavailable`, problem+json) — старт прогона на деплое, где шов движка не сконфигурирован;
временное состояние, ретрай позже, `Retry-After` не обещан. Зеркало `frontend/docs/api-contract/`
синхронизировано байт-в-байт этим же лендингом. При следующей сессии — перегенерировать типы из
спеки; других изменений форм нет, правка аддитивная.
- **Платформа-раннер заленден** (`d29e30c`): пять ручек `/v0` контракта живые — библиотека ·
карточка · run-options · старт прогона · usage; прогресс прогона пофазный (draft/edit) в карточке.
Фронт может говорить с живой платформой вместо моков — стык проверен 47 wire-проверками приёмки.
- Известное ограничение до эмиттера (строка 103): стоп по потолку и штатный останов приезжают как
`failed` (PD-113/двойник) — на экране не строить различение этих состояний до строки 165 движка.
## Пинг оркестратора №16 — 09.08.2026 (кросс-ссылка зонных половинок, строка 167)
Движковая половина темы Ф-30/В-4 («глава без заголовка») — **строка 160 единого бэклога** (`titleRaw` в манифест · provenance у heading · тип chapter/fragment; research/27 §6 Этап 0). До её лендинга `heading` манифеста = ВРЕМЕННЫЙ рендер движка (D39.122 п.2д) — честный заголовок из данных приедет строкой 160, продуктовое слово — В-4 на владельце. На экране ничего не менять до обоих.
## Пинг оркестратора №17 — 16.08.2026 (зона во фризе; контракт-ревью принято D39.138 — четыре ваших вопроса ОТВЕЧЕНЫ, входы разморозки)
Контракт-ревью API v0 отработало отдельной сессией и ПРИНЯТО (отчёт — `docs/research/28-contract-review.md`; решения владельца — его §8, ратификация D39.138). Заказан ЛОМАЮЩИЙ батч 0.3.0 (строка 183 единого бэклога) — типы перегенерируются после его лендинга; до него нормативной остаётся 0.2.3. ⚠ Читать ОРИГИНАЛ отчёта, не пересказ. По вашим строкам:
1. **Ф-56 (конец интейка):** Б-6(а) — поток перевешивается на КНИГУ (`GET /books/{id}/events`) с кадрами конца разбора и конца прогона и `204` на завершённом; ваш опрос — легитимное лечение до батча.
2. **Ф-57 (пары):** Б-2 — `GET /capabilities` (пары со статусом · порог интейка · форматы · размеры страниц · версия контракта); `languages.ts` станет чтением.
3. **Ф-61 (английские фразы):** В-1 решён владельцем вариантом B (§8 п.4): машинный `code` + `request_id`; `title`/`detail` — developer-facing, **фразу рисует клиент по словарю кодов** (ваша таблица `AddBook.tsx:282-288` становится нормой); после батча строка `AddBook.tsx:289` (`problem?.detail ?? problem?.title`) и её сёстры `Loaded.tsx:66`, `RunStart.tsx:188` СНИМАЮТСЯ.
4. **Ф-62 (переименование):** Б-5 — `PATCH /books/{id}` ТОЛЬКО с `title` (409 при живом прогоне) + `DELETE`; правка — отображение, до движкового брифа не доезжает. Жанр из продукта УХОДИТ совсем (Б-23, слово владельца 16.08) — поле формы снимется при разморозке.
5. **Ф-43 протух текстом:** движковая половина банка ПОСТРОЕНА ещё D39.122 (сайдкар `<db>.bank.json` + `bank-stop.json`), не хватает платформенной проекции (строка 169 единого бэклога, вход P7) — обновите текст строки.
6. **Решение владельца К-6 (§8 п.11):** замечания показывать ВСЕ; в тексте — сворачивать и раскрывать кнопкой; словарь ступеней заранее НЕ проектировать; зависимость `Note.id` закрывает батч. **Зарегистрируйте зонной строкой при разморозке.**
7. **Мок-находки §9 (чинить при разморозке):** отказ интейка триггерится маркером в ИМЕНИ файла (`mock/intake.ts:238`) — переключатель без аналога на сервере; стоп игнорирует `runId` (`mock/handlers.ts:190`); мир `scale`: чтения на ревизии 4102, кадры с 1841 — расходятся по построению (`mock/worlds.ts:136`); в `loading` любой POST уходит МИМО мока в реальную сеть (`handlers.ts:59`); переполнение обхода страниц = статус 0 = неотличимо от «сервер недоступен» (`client.ts:114` → `Loaded.tsx:65`); мок интейка считает ВСЕ части формы, платформа — только до файла (`intake.ts:212` против `v0.go:337-360`).
8. **Перф-входы S5 (§5б/Б-11а):** снять `refetchOnWindowFocus` для тяжёлых коллекций (замер: самый частый трафик порождает переключение вкладок, не пайплайн — 12 вкладок = 562 КБ на фокус) и поднять `staleTime` после появления ETag/304 у платформы; ErrorBoundary в зоне нет ни одного (Б-0: TypeError рендера при смене словаря волн) — завести при разморозке; 401 сегодня тупик без ссылки на вход (§4 №27) — зонная строка. Вопросы — через владельца.
**Аддендум к пингу №17 (16.08, свип планировочных доков D39.139):** (1) Три носителя зоны учат ПОФАЗНОМУ прогрессу «draft N/M ∥ edit N/M» — `FRONTEND_SESSION_PROMPT.md` §9 п.1, `FRONTEND_PLAN.md` §6 п.1, `STACK_DECISIONS.md` §8 п.1; после батча 0.3.0 это устареет (Б-0/D39.138: на проводе ОДИН счётчик до ближайшей остановки, знаменатель — купленный объём) — при разморозке обновить все три, не только код. (2) `STACK_DECISIONS.md` §8 протух целиком: все четыре пункта «достроить в движке» ПОСТРОЕНЫ (пофазные счётчики и манифест — D39.122; JSON таблицы подписи — `bank-stop.json` D39.122; TM_TRACE_ID — P6/D39.132). (3) Диспозиции строк: **Ф-59** — В-10 закрыт владельцем 16.08 «вежливость» (D39.138 п.2к: всё правильно, цена названа — строку закрыть); **Ф-37** — К-10 отвечен «НЕ строить» (поправка приёмки ревью: фазы уходят с провода и у главы — пометка черновика остаётся книжной, хвост пере-диспозиционировать); **Ф-39** — закрыта ещё словом владельца 15.08 (D39.136 п.4б: полей BankTerm не заводить, sense хватает; его калибровка — строка 178 единого). Вопросы — через владельца.
**Дописка к аддендуму (16.08):** гейт на утечку конвейера в провод — «на проводе нет имён стадий/волн и движковых словарей», машинный тест по образцу `generality.test.ts` — назначен вашей зоне (D39.138 п.2а; спек-сессия батча запишет правило в компаньон контракта). Строить при первом касании зоны вместе с синком зеркала и перегенерацией типов.
**Пинг оркестратора №17 — 16.08 (модель подписи банка, слово владельца; читать ПЕРЕД S5):** подписывается ВЕСЬ банк ОДНИМ действием юзера — черновой перевод + черновой банк появляются вместе после черновой волны, юзер смотрит банк, правит ТОЛЬКО то, что захотел, и жмёт один ОК (= resume) — перевод уходит в доработку; нерешённые термины едут как предложил сервис. Пер-термная масс-подпись сотен строк НЕ строится — это была инерция (владелец уже говорил зоне 10.08, снимая счётчики «подписано N»; теперь снята и из контракта: 409-гейт полноты убран, `pending_decisions`/`complete` информационные — D39.144). Строки Ф-44/Ф-45/Ф-46 при разморозке читать через эту модель: «действие подписи» = один ОК + опциональные точечные правки, НЕ проход по строкам. Пост-ридинговые правки банка («поправить/добавить термин → пере-генерация по вхождениям») — направление, механика не спроектирована нигде (полигон работает над точечным редактором) — экранов под неё не строить до отдельного слова. Вопросы — через владельца.
**Дописка к пингам №17 (16.08, по аудиту готовности зоны — ЧЕТЫРЕ нормы зоны сменили знак, читать ДО всего остального):** (1) **Канон контракта = 0.3.0, ЗАЛЕНДЕН (D39.142/143); ваше зеркало `docs/api-contract/` осталось на 0.2.3 РАТИФИЦИРОВАННО** (D39.142 п.5, на время фриза) — «зеркало = байт-копия» временно НЕ действует, нормативен только канон в `docs/architecture/14-api-contract/`; синк + перегенерация типов = первое касание зоны. (2) **Запрет клиентской метки «Глава {n}» СНЯТ каноном 0.3.0** — клиент теперь ОБЯЗАН сам рисовать порядковый в локали интерфейса, когда `heading`/`number` = null (Ф-30 и пинг №16 «на экране ничего не менять» — устарели; движковая строка 160 остаётся про НАСТОЯЩИЕ названия). (3) **Ф-31/В-6 закрыты ещё D39.132 п.2а** (`null` на проводе ратифицирован), а кадр `EventCeiling`, на который они опирались, снят 0.3.0 целиком — строки закрыть при разморозке. (4) **В-11 (фразы) пере-собрать на словарь 0.3.0**: карта «код → фраза» — приложение А компаньона; `parser_unavailable` переименован в `processing_failed`, добавлен `content_refused`. Плюс: **дев-стенд платформы СУЩЕСТВУЕТ с P6** (`tmplatformctl seed` + дев-вход, D39.132) — Ф-29 (снос моков) и Ф-18 (вес бандла) читать через него; статус зоны: ФРИЗ (D39.136 п.2), снятие = лендинг P7. Вопросы — через владельца.
**Пинг оркестратора №18 — 17.08.2026: ФРИЗ ПРОДЛЁН, разморозка отвязана от P7 (слово владельца, D39.147).** Прежнее условие «разморозка = лендинг P7 + гейт S5» БОЛЬШЕ НЕ ДЕЙСТВУЕТ: владелец 17.08 сказал морозить зону дальше — сначала движок и платформа доводятся до состояния «работают и отдают результат», и только потом фронт накручивается на готовую функциональность. Практически: **лендинг P7 зону не размораживает, промт S5 не выдаётся**, разморозка — отдельным словом владельца. Всё, что было записано как первое касание зоны (синк зеркала контракта 0.3.0 · перегенерация типов · моки · гейт утечки конвейера · фикс-лист ФС-1..12 · Ф-63/Ф-28 · пере-сборка фраз В-11 по словарю кодов), НЕ отменено — оно ждёт разморозки, а не P7. Направление, которое стоит знать заранее: моки при разморозке уступают реальному источнику — дев-стенд платформы существует с P6 (`tmplatformctl seed` + дев-вход), а форму «держать моки на уровне бэкендов или отдельно» владелец назвал направлением, но механику проектировать пока не просил. Живой smoke против дев-стенда остаётся легитимным и во фризе. Вопросы — через владельца.
**Пинг оркестратора №18 (второй) — 20.08.2026: фриз в силе, но зоне прилетели ДВЕ вещи из лендинга P7 и одно предложение по норме.**
1. **Контракт API — канон 0.4.0 РАТИФИЦИРОВАН** (D39.152). Зеркало зоны отстаёт ратифицированно и остаётся на 0.2.3 до разморозки; при первом касании — синк зеркала БАЙТ-В-БАЙТ (`cmp`) и перегенерация типов, как и было в перечне. Ломающее против 0.3.0: обязательное `Run.stop_requested` (плюс три поведенческих расхождения, тела — D39.152 п.5). Что это даёт экрану: кнопка «стоп» перестаёт врать — прогон помнит, что его просили остановить, и переживает перезагрузку страницы, поэтому «остановлено — работа на подписи банка, продолжить дёшево» рисуется по признаку, а не по догадке. И `resume` теперь отвечает двумя РАЗНЫМИ причинами: «прогон закончен, купите новый» против «пополните счёт» — фразы В-3 по словарю кодов пишутся уже под это.
2. **Читающая поверхность ПОСТРОЕНА и заленджена** (P7, D39.153): главы, юниты, замечания, проекция банка, поток событий SSE, модель ошибок с машинным `code`, условные чтения и сжатие, `Idempotency-Key`, `structure_version`. То есть триггер Ф-29 («полный снос `frontend/src/mock/`») по данным наступил — но РАЗМОРОЗКА ОТДЕЛЬНЫМ СЛОВОМ владельца, пинг №18 от 17.08 в силе, S5 не выдаётся. ⚠ Живой дев-стенд платформы существует и работает — при разморозке моки уступают ему, а не наоборот.
3. **Предложение по норме pre-commit хука (владелец не отвечал, поэтому это ПРЕДЛОЖЕНИЕ, а не решение).** В док-фрагмент хука 17.08 внесена строка «жалобы на хук — писать ВЛАДЕЛЬЦУ, а не тихо деградировать на воркэраунд или хак» (D39.148). Во фронтовом фрагменте хука такой строки нет. Смысл нормы: сессия, которой гейт мешает, обязана эскалировать, а не обходить — тихий обход выглядит как зелёный прогон и не виден ничем. Внести при первом касании зоны, если владелец не скажет иначе. ⚠ Записано здесь потому, что обязательство к ЧУЖОЙ зоне, живущее только в моей прозе, гейтами не видно по построению — поймано ревьюером полноты выгрузки на лендинге P7.
**Дописка к пингу №18-второму (20.08, свип доков при лендинге P7):** `frontend/docs/API_CONTRACT_INPUT.md` несёт собственный баннер «место такому — в архиве, перенос при ратификации делает оркестратор», а ратификация была ещё 04.08 — то есть перенос просрочен. ⚠ Испр. 21.08 по аудиту: первая редакция приписывала тот же баннер и `API_CONTRACT_DRAFT.md` — НЕВЕРНО, его баннер говорит противоположное («ИСПОЛНЕНО, канон живёт не здесь»), живых якорей D-нот в него нет, и довод про якорь на него не распространяется — он переносим хоть сейчас. **Не переношу и объясняю почему:** нота D39.153 п.7(б) цитирует `API_CONTRACT_INPUT.md:258-264` как первоисточник провенанса пер-термного гейта, а D-ноты append-only — перенос убьёт живой якорь и линт якорей покраснеет. Диспозиция: переносить при разморозке зоны ТЕМ ЖЕ касанием, что правит якорь в D39.153 на архивный путь. До тех пор оба файла живут по старым путям законно.