From 486a5d7bc27782bfbf085aa58012829eae21bb29 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Sun, 30 Aug 2026 14:24:59 +0000 Subject: [PATCH] docs: review document for #82 Issue: #82 User-Visible: no --- docs/reviews/SPEC-REVIEW-82-r1.md | 183 ++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 docs/reviews/SPEC-REVIEW-82-r1.md diff --git a/docs/reviews/SPEC-REVIEW-82-r1.md b/docs/reviews/SPEC-REVIEW-82-r1.md new file mode 100644 index 00000000..7b140d75 --- /dev/null +++ b/docs/reviews/SPEC-REVIEW-82-r1.md @@ -0,0 +1,183 @@ +# 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 → в задаче**