Files
houseplan-card/docs/reviews/SPEC-REVIEW-82-r1.md
T
2026-08-30 16:11:35 +00:00

184 lines
14 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.
# SPEC-REVIEW-82-r1 — Плавное масштабирование плана (issue #82)
- **Issue:** https://github.com/Matysh/houseplan-card/issues/82
- **Артефакт ТЗ:** `docs/specs/082-smooth-zoom.md`, коммит `141d79a923f5703eb3beceebdabbd5508821f0fe`
- **Заход:** r1 · блокирующих циклов израсходовано 0 из 4 (полный трек, лимит 4)
- **Ревьюер:** Claude, роль «Ревьюер ТЗ» (PROCESS.md §2.4, §6)
## Скоуп ревью
Задача полного трека (нет метки `small`), поэтому ТЗ живёт файлом
`docs/specs/082-smooth-zoom.md`, а не в теле issue. Это первый заход
ревью на этом ТЗ (r1), поэтому §2.10 (разбор по дельте) не применяется —
разбор полный. Диф на пути к текущему SHA:
```
git diff 453c3e3d..141d79a9 -- docs/specs/082-smooth-zoom.md # 352+/232- строк, актуализация ТЗ
```
Диф не трогает `src/**`, `custom_components/**`, `test/**`, `demo/**` —
только `docs/specs/082-smooth-zoom.md`. Класс C (документация), гейты
типа `typecheck`/`test`/`build`/`check-docs` к этому диффу неприменимы:
менять нечего, кода не существует. См. «Чего не проверял».
## Как проверялось
1. Прочитан `docs/SCOPE.md`, `AGENTS.md`, `PROCESS.md` (§1, §2.3–2.10, §4,
§5, §7, §12).
2. Прочитано тело issue #82 и все три комментария (аналитика 2026-08-14,
заведение ТЗ 2026-08-15, актуализация 2026-08-30).
3. Прочитан полный текущий текст `docs/specs/082-smooth-zoom.md` (24
раздела).
4. Прочитан канонический `docs/CANVAS.md` (§5 Zoom and pan, «View/editor
camera handoff», §4 content frame) и `docs/TOUCH-SUPPORT.md` (raздел
про View/editor visual transition, deliberate degradation rule).
5. Проверены фактические утверждения ТЗ о текущем коде против
`src/houseplan-card.ts` (`_zoomAt`, `_onWheel`, `_stepZoom`,
`_resetZoom`, `_fitAll`, `_fitFar`, `_baseVb`, `_clampView`,
`ZOOM_MAX`/`ZOOM_MIN`, `LS_ZOOM`, `_saveZoom`, lazy `import('./houseplan-editor-runtime')`)
и `src/mode-transition.ts` (`ModeTransitionController`,
`interpolateModeVisualState` — уже интерполирует `pixelsPerUnit` в
log-space и center линейно тем же easing, что подтверждает
реализуемость предложенного §9 механизма).
6. Проверена терминология кнопок/подсказок против `src/i18n/ru.json`
(`title.zoom_fit` = «Вписать всё», `canvas.show_far` = «Показать») —
совпадает с матрицей §6 ТЗ.
7. Проверено существование смоков, на которые ссылается план тестов
(`demo/smoke_mode_transition.mjs`, `demo/smoke_visual_continuity.mjs`,
`demo/smoke_zoom_out.mjs`, `demo/smoke_pan_any_zoom.mjs`,
`demo/screencast_visual_continuity.mjs`, `npm run continuity:screencast`
в `docs/TESTING.md`) — не изобретены, это существующий инструментарий
#73.
8. Проверены обязательные разделы ТЗ по PROCESS.md §7.1 построчно
(список ниже).
## Проверка обязательных разделов (§7.1)
| Раздел §7.1 | Есть в ТЗ | Где |
| --- | --- | --- |
| Сценарий (персона/поверхность/момент) | ✅ | §1 |
| Что человек увидит до/после | ✅ | §2 |
| Проблема | ✅ | §3 |
| Скоуп и не-скоуп | ✅ | §4 (цели) + §5 (не входит) |
| Контракт поведения / UX | ✅ | §6–§13 |
| Модель данных и миграция | ✅ | §14 — «не меняется, миграции нет» |
| i18n | ✅ | §20 — новых ключей нет |
| AC1…ACn с доказательством | ✅ | §17, 14 критериев, у каждого назван способ |
| План автотестов | ✅ | §18 (unit / browser smoke / golden-perf) |
| Риски | ✅ | §22, 8 рисков с мерой |
| Откат | ✅ | §23 |
| Release-артефакты | ✅ | §21 |
Все обязательные разделы присутствуют и содержательны, не переписывают
issue дословно.
## Находки
Блокирующих (High) находок нет. В скоупе-Medium находок нет. Вне
скоупа — нет.
Ниже — три Low-наблюдения; ни одно не требует правки ТЗ, оставлены с
записью решения ревьюера (не блокируют переход в `S5-ready`).
### Low-1 — AC13 частично доказывается гейтом, недоступным на этой стадии цикла
`AC13` называет доказательством «Performance profile + screencast
smoke». Per `docs/STATUS.md`, CDP-скриншот-профиль (`continuity:screencast`)
— **stable-release-only** гейт, а не гейт код-ревью или даже бета-гейта;
то есть формально AC13 не может быть закрыт автотестом до промоушена в
стабильный релиз. Это не изобретение автора ТЗ: тот же паттерн уже
принят для #73 (`docs/superpowers/specs/2026-08-10-plan-visual-continuity-design.md`
явно делит проверку на обязательный CI rAF sampler и pre-stable CDP
screencast). Решение ревьюера: не блокировать — прецедент уже
принят продуктом, а перформанс-часть AC13 (RAF/rebuild-счётчики) всё
равно доказывается раньше, в pre-beta профиле (§8). Отметить только,
что на код-ревью AC13 будет разобран по коду плюс перформанс-профиль,
а screencast-часть закроется не раньше стабильного гейта — это стоит
явно писать в хендоффе, а не подразумевать.
### Low-2 — общий easing-хелпер между `ModeTransitionController` и новым camera controller не специфицирован технически
§24 помечает разделение camera/mode-контроллеров с общим easing как
«принято предположительно, поменять свободно» — формально корректно
по PROCESS.md §7.1 (технический вопрос, не продуктовый). Замечание
чисто наблюдательное: `interpolateModeVisualState` в
`src/mode-transition.ts:124-156` уже реализует ровно ту же схему
(log-space для масштаба, линейно для центра, общий `ease()`), так что
риск, который §22 таблицы называет «Wheel ощущается медленным» /
«SVG и HTML расходятся», технически прецедентно снят — эта же формула
уже работает в проде для перехода режимов. Не требует правки ТЗ.
### Low-3 — «дальний hint «Показать»» добавлен в матрицу §6, не упомянутый в исходном тексте issue
Матрица §6 ТЗ добавляет девятую строку («Far hint «Показать»»)
относительно восьми строк в исходном issue. Проверено по коду:
`_fitFar()` (`src/houseplan-card.ts:5879`) сам вызывает `_resetZoom()`
— тот же примитив, что и «Вписать всё»/home-arrow/double-tap, так что
это не новая функциональность, а актуализация того, что «Вписать всё» в
issue уже подразумевало устройство разных источников одного и того же
действия. Не расширение скоупа, не требует нового вопроса владельцу.
## Что проверено и корректно
- Все фактические утверждения раздела 3 «Актуальность и проблема» о
текущем коде (`_zoomAt`, `_onWheel`, `_stepZoom`, `_resetZoom`,
`_fitAll`/`_fitFar`, lazy editor runtime, общий `_view` для
flat/isometric) — сверены с исходным кодом и точны.
- Константы `MIN_ZOOM = 1/3`, `ZOOM_MAX = 8`, easing
`cubic-bezier(0.2, 0.7, 0.2, 1)` — совпадают с `docs/CANVAS.md` §5 и
`src/mode-transition.ts`.
- Persistence-контракт §13 («editor zoom не пишется в View intent»,
«`_saveZoom()` работает только в `mode === 'view'`») сверен с
`src/houseplan-card.ts:6212-6228` — комментарий в коде подтверждает
тот же инвариант дословно.
- Терминология кнопок («Вписать всё», «Показать») сверена с
`src/i18n/ru.json` — совпадает буквально.
- `docs/TOUCH-SUPPORT.md` не противоречит требованию §12 «stage не
получает overlay/inert» во время camera-only tween: канонический
`inert` относится к отдельному, другому контракту View/editor
mode-перехода (#101), а не к zoom-действию внутри режима — ТЗ
корректно разграничивает эти два случая в §8.
- AC1–AC14 однозначны, у каждого указан способ доказательства; ни
одна формулировка не читается как два разных критерия одновременно.
- Раздел 24 «Принятые технические предположения» корректно отделяет
технические решения от продуктовых; продуктовых вопросов к
владельцу действительно не осталось — сценарии из issue (interruption
matrix, accessibility, no-op) уже были фактами, подтверждёнными
комментарием владельца 2026-08-14 («вопросы: нет»).
- Раздел «Не входит в задачу» корректно исключает inertia/kinetic pan,
анимацию mode/space/projection-переходов, новый storage-формат,
что не даёт скоупу расползтись на смежные issue (#101, #73, #89/122).
- Двунаправленные ссылки issue ↔ ТЗ на месте (`docs/specs/README.md`
строка 115, тело ТЗ строка 3).
## Чего не проверял
- **Код-гейты `typecheck`/`test`/`build`/`check-docs` не прогонялись** —
диф этого раунда состоит только из `docs/specs/082-smooth-zoom.md`
(класс C), продуктового кода/тестов нет, прогонять нечего. Это
сознательное решение по объёму, а не пропуск: `git diff --stat`
выше подтверждает единственный изменённый файл.
- Не проверялась реализуемость точной wheel-anchor математики
(0.5 CSS px) на реальном RAF-цикле — это вопрос будущей реализации
и код-ревью («тест умеет падать»), не спецификации: ТЗ формулирует
требование измеримо (AC4, unit на presented-state retarget), способ
доказательства назван.
- Не запускал browser/perf/golden-смоки — на этой стадии кода нет,
им неоткуда взяться; они будут частью реализации (§18) и предметом
код-ревью.
- Не проверял детально `iso-projection.ts` построчно на предмет
скрытых зависимостей от zoom помимо общего `_view`/`_zoom`
состояния — ограничился подтверждением, что модуль не содержит
собственных ссылок на `viewBox`/`zoom` (grep пуст), что достаточно
для вывода «камера едина для flat/iso» из §9/AC10.
## Вердикт
ТЗ полное, разделы §7.1 закрыты, критерии приёмки однозначны и
снабжены способом доказательства, продуктовых вопросов к владельцу не
осталось, фактические утверждения о текущем коде и канонических
документах проверены и точны. Блокирующих находок нет.
**Вердикт: зелёный · заход r1 · блокирующих циклов 0/4 · High: 0 ·
Medium: 0 → в задаче**