docs: review document for #742

Issue: #742
User-Visible: no
This commit is contained in:
claude[bot]
2026-10-01 05:14:49 +00:00
parent 0621d53a49
commit 76558bf2a0
2 changed files with 187 additions and 1 deletions
+2 -1
View File
@@ -1,10 +1,11 @@
# Индекс ревью # Индекс ревью
Генерируется `node scripts/reviews-index.mjs` (#635) — не редактировать руками. Документов: 233, issue: 113. Вердикт: 🟢 зелёный · 🟡 жёлтый · 🔴 красный · ⚪ не распознан (свободная форма старых документов). H/M — число High/Medium по строке вердикта или заголовкам находок. Файлы — пути, названные в находках; ищите по имени файла: `grep form-kit INDEX.md`. Генерируется `node scripts/reviews-index.mjs` (#635) — не редактировать руками. Документов: 234, issue: 114. Вердикт: 🟢 зелёный · 🟡 жёлтый · 🔴 красный · ⚪ не распознан (свободная форма старых документов). H/M — число High/Medium по строке вердикта или заголовкам находок. Файлы — пути, названные в находках; ищите по имени файла: `grep form-kit INDEX.md`.
| Issue | Документ | Этап · раунд | Вердикт | H | M | Находки | Файлы | | Issue | Документ | Этап · раунд | Вердикт | H | M | Находки | Файлы |
|---|---|---|---|---:|---:|---|---| |---|---|---|---|---:|---:|---|---|
| бета v1.79.0-beta.1 | [SHIP-REVIEW-v1.79.0-beta.1.md](SHIP-REVIEW-v1.79.0-beta.1.md) | пакетное ревью ship · — | ⚪ — | 0 | 0 | — | — | | бета v1.79.0-beta.1 | [SHIP-REVIEW-v1.79.0-beta.1.md](SHIP-REVIEW-v1.79.0-beta.1.md) | пакетное ревью ship · — | ⚪ — | 0 | 0 | — | — |
| #742 | [SPEC-REVIEW-742-r1.md](SPEC-REVIEW-742-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | устаревшее число в AC6 (не блокирует) | `src/houseplan-card.ts` `test/core-file-budget.test.mjs` |
| #740 | [SPEC-REVIEW-740-r1.md](SPEC-REVIEW-740-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | устаревший номер строки в «Проблема», п.2 | `src/stairs-view.ts` `src/stairs-editor.ts` `stairs-view.ts` `stairs-editor.ts` `stairs.ts` `large-house.mjs` `matrix.mjs` | | #740 | [SPEC-REVIEW-740-r1.md](SPEC-REVIEW-740-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | устаревший номер строки в «Проблема», п.2 | `src/stairs-view.ts` `src/stairs-editor.ts` `stairs-view.ts` `stairs-editor.ts` `stairs.ts` `large-house.mjs` `matrix.mjs` |
| #739 | [SPEC-REVIEW-739-r1.md](SPEC-REVIEW-739-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — | — | | #739 | [SPEC-REVIEW-739-r1.md](SPEC-REVIEW-739-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — | — |
| #737 | [SPEC-REVIEW-737-r1.md](SPEC-REVIEW-737-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — | — | | #737 | [SPEC-REVIEW-737-r1.md](SPEC-REVIEW-737-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — | — |
+185
View File
@@ -0,0 +1,185 @@
# SPEC-REVIEW-742-r1
Issue: #742 — «Первые кадры после загрузки: комната на кадр-два без заливки
(белая бумага)» · Этап: spec · Заход: r1 · Трек: `track:ask` (предложен
агентом, критерий §5 «перф»; владелец не подтверждал строкой — метка остаётся
предложением) · блокирующих циклов израсходовано 0 из 4.
## Материал раунда
ТЗ — тело issue #742, раздел `## ТЗ` (целиком, включая «Итог исследования»,
«Доказательства», «Скоуп/Не-скоуп», «Контракт поведения», АС1–АС6, «Принято
предположительно»). Кода нет: ветки `issue/742-*` не существует, задача на
`S4-spec-review` впервые. Факты сверялись с текущим `HEAD` репозитория
(`f3cfb93e947c591a7ce1a73bae2d081e649a2332`), а не только с заявленным в ТЗ
`origin/dev` `b3dd9444`, — между ними лёг #725 (`235f60e6`), который тоже
трогает `src/houseplan-card.ts` на описываемом горячем пути.
## Скоуп проверки
1. Обязательные разделы §7.1 — присутствие и соответствие шаблону, принятому
в проекте (сверено с #725, чей ТЗ-ревью зелёный, `legacy`/`docs/reviews`).
2. Однозначность и доказуемость каждого AC1–AC6; falsifiability критериев.
3. Фактическая точность технических утверждений ТЗ против текущего кода:
номера строк, имена функций/констант, поведение валидации бэкенда,
существующие файлы (смоки, реестр мутаций, бюджет ядра).
4. Правило §7.1 о расколе продуктовых/технических вопросов и отсутствии
догадок, записанных как факт.
5. Соответствие `docs/SCOPE.md` (какую строку Core user jobs закрывает) и
отсутствие расширения продукта за пределы контракта К1–К4.
6. Применимость §7.1 про дефект растра/композитинга (#690) — обоснованность
отказа от владельческого подтверждения в GPU-браузере.
## Как проверялось
Чтением, не исполнением — на этапе spec кода нет, гейты (`tsc`, `npm test`,
`npm run build`, смоки, мутанты, perf) не прогонялись: прогонять нечего
(`docs/process/REVIEWER.md` «Ревью ТЗ» не требует гейтов; §8 касается кода).
Для каждой технической ссылки ТЗ — прямое чтение файла и строки на HEAD:
| Утверждение ТЗ | Файл:строка в ТЗ | Проверено на HEAD | Результат |
|---|---|---|---|
| `.room { transition: 0.12s; }` | `src/styles/plan.styles.ts:399–400` | да | совпадает дословно |
| Список фигур комнат — `map()` без ключей | `src/houseplan-card.ts:10931` | да | `space.rooms.filter(...).map((r) => {` на строке 10931, подтверждено; структура не изменилась после #725 |
| Комментарий #525/#534 называет только проёмы, не комнаты | `plan.styles.ts:473–493` | да | комментарий о `.op-leaf`, комнаты не упомянуты — задача на добавление верна |
| `.zoomwrap` слайд 0.18s | `plan.styles.ts:594–595` | да | совпадает |
| `_cycleTick` → `_slideTo`, `reduce` без правила для `.room` | `houseplan-card.ts:1653`, `:1457` | да | подтверждено, `_slideTo` вызывается из `_cycleTick`; `if (reduce) return true;` до переходов |
| `_commitSpace` сбрасывает hover/focus | `houseplan-card.ts:1419–1426` | да | совпадает (со сдвигом на пару строк из-за промежуточных правок, по смыслу то же) |
| `DEFAULT_CUSTOM_FILL = { c: '#607d8b', a: 0.18 }` | `src/logic.ts:1301` | да | совпадает |
| `room.id || #${index}` | `src/clean-floor.ts:32` | да | совпадает (`roomKey = room.id || `#${space.rooms.indexOf(room)}``) |
| `data-id` поиск в `room-fit.ts:131` | `src/room-fit.ts:131` | да | совпадает |
| `ROOM_SCHEMA` требует `id`, но `_TEXT` пропускает пустую строку; уникальность пустых `id` не проверяется | `validation.py:1349, 1241 (переиспользован _TEXT), 1729–1739` | да | `_TEXT = vol.All(str, vol.Length(max=MAX_TEXT))` — не `_NONEMPTY_TEXT`; `_space_geometry_invariants` делает `if not item_id: continue`, что подтверждает пропуск проверки для пустых id |
| `openings-rendered-without-keys` — образец для новых мутантов | `scripts/mutation-registry.mjs:9829` | да | существует, имя `rooms-rendered-without-keys`/`rooms-rendered-without-space-key` свободно (нет коллизий) |
| Потолок `src/houseplan-card.ts` 12896, факт 12 874 | `test/core-file-budget.test.mjs` | частично | потолок 12896 подтверждён; факт на HEAD — **12879** строк (мера теста, `split('\n').length`), не 12874. Расхождение в 5 строк из-за #725, влившегося после сверки ТЗ с `b3dd9444` (на том SHA файл давал 12875 — тоже не точно 12874, на строку больше). Не блокирует: гейт — `cap + band` = 12896 + 50 = **12946** (`coreBudgetViolations`), запас с HEAD 67 строк, заведомо достаточно для правки вида «обернуть map в `keyed(repeat(...))`» (та же правка для проёмов стоила `+1` строку на уже присутствующий импорт `keyed`, который в файле уже есть) |
| Смоки из списка «известные красные песочницы» (AC4) и свидетели (AC1–AC3, perf) существуют | `demo/smoke_*.mjs` | да | все перечисленные файлы на месте: `smoke_summary_dialog_scroll`, `smoke_summary_first_paint`, `smoke_infinite_canvas`, `smoke_live_pan_coverage`, `smoke_space_switch_transitions`, `smoke_daycycle_layer_budget`, `smoke_render_perf`, `smoke_visual_continuity` |
| `docs/USER-GUIDE.ru.md` не описывает переходы при смене этажа | — | да | нет упоминаний мигания/перетекания заливки у переключения вкладок этажей; правка не требует правки гайда |
| `legacy/reviews/v1.75.0/CODE-REVIEW-534-r1.md`, `v1.74.0/SPEC-REVIEW-525-r1.md` существуют | — | да | оба файла на месте |
| `docs/reviews/INDEX.md` по #525/#534/#694/#725/#735 без открытых находок, блокирующих #742 | — | да | #725 закрыт зелёным на обоих этапах (найдена и снята только стилистика — устаревший номер строки, прецедент того же класса, что и находка ниже); #694 закрыт зелёным после r2 |
| Шаблон разделов ТЗ (`### UX · данные · i18n · touch` одной строкой) | §7.1 требует UX / модель данных и миграция / i18n тремя пунктами | — | совпадает с принятым в проекте шаблоном — тот же заголовок использован в принятом (зелёном) ТЗ #725; не находка |
## Находки
### Low-1 — устаревшее число в AC6 (не блокирует)
- **Файл/место:** тело issue #742, таблица AC, строка AC6: «потолок
`src/houseplan-card.ts` в `test/core-file-budget.test.mjs` не поднимается
(12 874 строки, потолок 12 896)».
- **В чём неточность:** на HEAD материала (`f3cfb93e`) файл даёт **12879**
строк мерой теста (`split('\n').length`), не 12874. ТЗ сверялось с
`origin/dev` `b3dd9444` (где факт был 12875, тоже не 12874 — похоже на
ручной подсчёт `wc -l` без +1 на конечный перевод строки), а после той сверки
в `dev` влился #725, прибавивший ещё 4 строки к этому же файлу.
- **Почему не блокирует:** реальный гейт — `cap + band` = 12896 + 50 = 12946
(`coreBudgetViolations`, `test/core-file-budget.test.mjs:77-91`), а не голый
потолок 12896. Запас от текущего факта (12879) до реального порога — 67
строк; описанная правка (обернуть `.map()` в `keyed(repeat(...))`, по
образцу проёмов/маркеров из #534) исторически стоила около одной строки на
уже присутствующий импорт. Риска упереться в потолок на этой задаче нет.
- **Что сделать:** автору — поправить число в AC6 на актуальное перед тем, как
брать задачу в работу (к моменту ветвления оно снова сдвинется, если `dev`
уйдёт вперёд; ревьюер кода пересчитает факт на своём SHA независимо от
этого ТЗ). Это редакционная, не содержательная правка — не возвращаю цикл
ради неё одной.
Других High/Medium не найдено. Класс «догадка, записанная как факт» (§7.1) не
обнаружен: все технические утверждения ТЗ подтверждены либо прямым чтением
кода, либо задокументированными «временными зондами» с результатами (таблица
«Доказательства» в теле issue) — это не единичный случай headless-доказательства
«на слово», а пять независимых экспериментов с конкретными числами кадров и
цветов.
## Что проверено и корректно
- **Обязательные разделы §7.1** — все присутствуют: сценарий, что человек
увидит до/после, проблема, скоуп/не-скоуп, контракт поведения (К1–К4),
UX·данные·i18n·touch (единым разделом — принятый в проекте шаблон, сверено с
зелёным #725), граничные случаи, критерии приёмки с доказательством и
oracle, план автотестов, затронутые файлы, производительность и бюджеты,
риски, откат, release-артефакты, «принято предположительно».
- **Каждый AC однозначен и привязан к конкретному, воспроизводимому
наблюдению**: AC1–AC3 называют точный смок-файл, точное действие
(`_pickSpace`, вставка комнаты, смена `custom_fill`), точный oracle
(отсутствие `CSSTransition`, сохранение `data-id`, вычисленный `fill`/
`fillOpacity`) и то, что делает их красными на `dev` сегодня. AC4 —
регрессионный список + `smoke-select`. AC5 — конкретная команда
(`performance.yml`) и обязательная публикация медиан в issue. AC6 — гейт и
два именованных мутанта с ролью каждого (внутренний/внешний ключ).
- **К1–К4 различимы и непротиворечивы** друг другу и «не-скоупу»: уход
перехода **внутри** этажа (К3) явно не трогается, отдельно от смены этажа
(К1/К2); пограничные случаи (совпадающий `id` на двух этажах, комната без
`id`) описаны и привязаны к конкретным AC.
- **Правило §7.1 о продуктовых/технических вопросах** соблюдено: раздел
«Вопросы владельцу» пуст с обоснованием («поведение на смене этажа уже
решено #525, поведение внутри этажа не меняется»), а все технические развилки
(форма правки, вид ключа, расположение свидетеля, судьба правил #734) вынесены
в «принято предположительно» как право ревьюера их оспорить, а не владельца
решать. Я не нашёл технического решения в этом списке, которое стоило бы
оспаривать: форма (`keyed(space.id, repeat(...))`) — уже проверенный в
проекте паттерн (#534), а не новое изобретение.
- **Отказ от владельческого подтверждения в GPU-браузере (§7.1, #690)**
обоснован по существу: симптом воспроизведён и объяснён на уровне
вычисленных CSS-стилей и `getAnimations()`, растр/композитинг/GPU в цепочке
причины не участвуют (отдельно зафиксировано и проверено экспериментом
«отключение перехода убирает белый кадр»), значит дефект не подпадает под
категорию, которая требует подтверждения в реальном браузере владельцем.
- **Трек `ask`** обоснован корректно по критерию «перф» §5: правка меняет
жизненный цикл узлов на горячем пути, предыдущая аналогичная правка (#525)
дала измеримый регресс, который чинила отдельная задача (#534). Понижение до
`show` — явно оставлено на усмотрение владельца, что соответствует правилу
«повышает любой агент, понижает только владелец».
- **Соответствие `docs/SCOPE.md`:** работа — полировка J1/J2 («что происходит
прямо сейчас», живой план без визуального шума/ложного сигнала) и J6 (план
остаётся верным при естественной работе интерфейса — переключении этажей).
Новых поверхностей, сущностей или продуктовых понятий не вводится, значит
граница скоупа не пересекается.
- **Факты из ТЗ, проверенные против кода** (таблица выше) — все совпадают,
кроме одной устаревшей цифры (Low-1). В частности подтверждена корневая
причина (позиционное переиспользование узла Lit + переход на все свойства
`.room`) и то, что существующий свидетель #525 (`onlyTheSwitchItselfAnimates`)
не ловит именно этот случай по названной в ТЗ причине (разные ветки шаблона
до/после `physicalize`).
- **Release-артефакты**: `User-Visible: yes` заявлен и текст RU/EN для
changelog уже готов в ТЗ; разделы «Не выпущено»/«Unreleased» в обоих
changelog-файлах на месте и пусты, правка впишется без конфликта.
## Чего не проверял
- **Любые гейты кода** (`tsc --noEmit`, `npm test`, `npm run build`, смоки,
мутанты, perf-профили, `pytest tests_backend`, инварианты модели) — на
этапе `spec` кода нет, ветки `issue/742-*` не существует, гейты не
прогонялись и не должны: это обязанность код-ревью.
- **Численные пороги AC5** (конкретные медианы `spaceSwitchMs`,
`switchCycleMs`, `longTask.countP95`) — они появятся только на коде; ТЗ
требует их опубликовать, но содержательно сравнить не с чем на этом этапе.
Прогон #735 (упомянут как риск: «`switchCycleMs` станет тёплым, AC5 станет
чувствительнее») тоже не перепроверялся — вне материала этого ревью.
- **Ветвление на реальных пяти шаблонах SVG-фигуры комнаты** (`path`/`path`/
`polygon`/`polygon`/`rect`, `houseplan-card.ts:11004–11034`) не прогонялось
на конкретной демо-фикстуре, чтобы независимо подтвердить, что первые
комнаты обоих этажей действительно попадают в одну и ту же ветку
(`polygon` по `r.poly`), как утверждает AC1. Это утверждение опирается на
таблицу «Доказательства» автора (пять зафиксированных экспериментов с
числами) — принято без переисполнения, это объём разбора ТЗ, а не кода.
- **Визуальное/ручное наблюдение в браузере** — не требуется этим ТЗ (К4 +
AC4, golden не заказан) и не является гейтом ревью ТЗ.
## Вердикт
Зелёный. Единственная находка (Low-1) — редакционная неточность числа,
не влияющая на выполнимость или проверяемость AC6, с объяснением и
рекомендацией автору поправить при входе в разработку; цикл за неё не
открываю.
---
<!-- material-anchors: сгенерировано конвейером (#414) -->
## Материал раунда
- Ветка: `dev`, коммит `f3cfb93e947c` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
- Дерево материала: `e50939c8bb3f8b4e29a26f71023bb9d69ee511d5`
```
git log --all --format='%H %T' | grep e50939c8bb3f
```
- Тело issue: `e1e4ad3459d8d681dab722e8636915bb56a64599c10e9c2ede34ef4e031e2456`
- Вердикт конвейера: `green` · High 0 · маршрут `fix`