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

14 KiB
Raw Blame History

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 → в задаче