Files
houseplan-card/docs/reviews/SPEC-REVIEW-122-r1.md
T
2026-08-13 21:04:32 +00:00

242 lines
21 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-122-r1
- **Issue:** https://github.com/Matysh/houseplan-card/issues/122
- **ТЗ под ревью:** `docs/specs/122-isometric-stage2.md` (коммит `76ce755`,
ветка `issue/122-isometric-stage2`)
- **Роль:** ревьюер ТЗ (не автор), этап `S4-spec-review`
- **Трек:** обычный (не `small`) — аналитика владельца оценила сложность и
риск 9/10, поверхностей больше одной (рендер/геометрия/UX/perf); лёгкий трек
корректно не применён, `docs/specs/<NN>-*.md` присутствует
- **Цикл:** r1/4 (полный трек, лимит 4)
## Скоуп ревью
Проверялось соответствие ТЗ:
- `docs/SCOPE.md` — попадание в Core user jobs (J1/J2/J3), узкое
owner-approved исключение из фотореалистичного/3D-запрета, инвариант lock;
- `PROCESS.md` §2.4/§2.5 (DoR), §7.1 (обязательные разделы ТЗ), §12
(запреты), §3 (правила 1, 2, 6, 9);
- `AGENTS.md` — классы файлов (только `docs/**` в этом коммите), ветка,
трейлеры;
- нормативному предшественнику `docs/specs/089-isometric-view-stage1.md` и
`docs/adr/089-isometric-stage1-renderer.md` — что Stage 2 не переписывает
принятые решения Stage 1 задним числом;
- каноническим документам затронутой подсистемы: `docs/ISOMETRIC.md`,
`docs/WALL-THICKNESS.md`, `docs/LIGHT.md`, `docs/TOUCH-SUPPORT.md`,
`docs/UX-MODES.md`;
- `docs/USER-GUIDE.ru.md` — что видимого пользователю текста не появляется и
документ не должен меняться;
- фактическому состоянию кода (`src/render/opening-symbol.ts`, `src/logic.ts`,
`src/labs.ts`, `demo/golden/matrix.mjs`) — на предмет того, что технические
утверждения ТЗ не являются непроверенной догадкой;
- треду issue #122 целиком, включая аналитику S2, вопросы владельца Q0–Q6 и
их принятие, а также связанному issue #124 (performance-блокер).
## Как проверялось
1. Прочитан весь тред issue #122: аналитика (ценность 7/10, P2, сложность
9/10), пакет вопросов владельцу Q0–Q6 с default-вариантами, принятие всех
default'ов владельцем 2026-08-13, хендофф автора «ТЗ готово к ревью».
Подтверждено, что ни один вопрос не был техническим, замаскированным под
продуктовый: Q0 (приоритет/ценность), Q1 (объём видимого сравнения
Stage1/Stage2 — второй флаг или нет), Q2 (что задают референсы: материал
или замена содержимого), Q3 (визуальное представление проёмов), Q4 (новый
декоративный свет — да/нет), Q5 (floor edge/тени), Q6 (деградация) — все
про то, что видит пользователь, и про объём этого issue.
2. Сверены обязательные разделы ТЗ (§7.1 `PROCESS.md`) — таблица ниже.
3. Прочитан `docs/specs/089-isometric-view-stage1.md` целиком и
`docs/ISOMETRIC.md` — подтверждено, что Stage 2 ссылается на реальные
решения Stage 1 (`wallBodiesGeometry()`, единая проекция, fingerprint без
`_cfgEpoch`/HA state, LRU-кэш на 8 сцен, latched flat fallback,
`projectedFrame()`, Labs-грамматика `iso`/`since 1.62.0`/`expires 1.65.0`)
и не выдаёт их за собственное изобретение и не переписывает Stage 1 задним
числом (ADR-89 не трогается, заводится новый `docs/adr/122-*.md`).
4. Прочитан `src/labs.ts` (`since: '1.62.0'`, `expires: '1.65.0'`) и
`package.json` (`version: 1.63.0`) — утверждение ТЗ «expiry не расширяется,
`1.65.0-beta.1` уже мёртв» технически корректно и согласуется с описанным в
`docs/ISOMETRIC.md` числовым сравнением ядра версии.
5. Прочитан `src/render/opening-symbol.ts` — подтверждены буквально: gate
открывается ровно на 10° (`10 * amount`, `docs/specs/122:213-215` против
`opening-symbol.ts:97`), window — двухстворчатый casement
(`rotate(${-90*amount})`/`rotate(${90*amount})`, `opening-symbol.ts:83-89`
против §6.5 «two-leaf/casement»). Это не догадка автора, а точное описание
существующего кода.
6. Прочитан `openingAmount()` в `src/logic.ts:316-323` — подтверждено
поведение «no contact → door/gate open (1), window closed (0)», которое ТЗ
называет «static-open default when no contact exists» (§6.5, Door/Gate).
7. Прочитан `docs/LIGHT.md` и `docs/WALL-THICKNESS.md` — подтверждено, что
«один регион света на источник», «wallBodiesGeometry как единственный
источник тела стены», «exterior silhouette из union центральных линий» —
реальные, а не придуманные инварианты, на которые ТЗ ссылается в §6.3, §6.7,
§7.
8. Прочитан `docs/TOUCH-SUPPORT.md` целиком — формулировки ТЗ §6.8
(«pointer/focus/ARIA inert», «View и kiosk остаются полностью
поддерживаемыми», «touch-only failure — product defect») дословно
отражают контракт, а не изобретены заново.
9. Прочитан `docs/USER-GUIDE.ru.md` — поиском подтверждено отсутствие каких-
либо упоминаний изометрии/объёмного вида; утверждение ТЗ §9 «документ
остаётся молчащим про скрытый Iso» верно на текущий момент.
10. Проверено существование golden-сцены `isometric-no-borders-dark` в
`demo/golden/matrix.mjs:23` — AC15/§12.3 ссылаются на реальный, а не
вымышленный сценарий.
11. Прочитан issue #124 (`gh issue view 124`) — подтверждено: воспроизводимый
performance-регресс `viewToggleMs.median 192.8мс` vs лимит `131.7мс` на
exact-SHA профиле `large-house-isometric-v1`, статус `S1-new` (ещё не
проанализирован). ТЗ §10 корректно описывает его как DoR-блокер
реализации (не ревью), с двумя явными путями снятия (закрытие #124 или
отдельное явное решение владельца) — ни то, ни другое не подменяет и не
ослабляет существующий бюджет.
12. Проверено `docs/specs/README.md:80` — строка на #122 добавлена в том же
коммите, ссылка issue ↔ ТЗ двусторонняя.
13. Проверены трейлеры коммита `76ce755`: `Issue: #122`, `User-Visible: no`;
`git show --stat` подтверждает изменение только `docs/specs/122-*.md` и
`docs/specs/README.md` — класс C, продуктовый код (класс A) не менялся,
правило №1 `AGENTS.md`/`PROCESS.md` соблюдено на этапе `spec`.
## Обязательные разделы (§7.1 PROCESS.md)
| Раздел | Есть | Комментарий |
|---|---|---|
| Сценарий (персона/поверхность/момент) | ✅ | §1 |
| Что человек увидит до/после (без терминов реализации) | ✅ | §1, одной фразой |
| Проблема | ✅ | §2 |
| Скоуп / не-скоуп | ✅ | §4 / §5 |
| Контракт поведения | ✅ | §6 (8 подразделов) |
| UX | ✅ | §9 (явно: нет нового UI/i18n) |
| Модель данных и миграция | ✅ | §8 |
| i18n | ✅ | §9 (пусто, обосновано) |
| AC1…ACn с доказательством | ✅ | §11, 16 штук, каждый с типом |
| План автотестов | ✅ | §12 (unit/smoke/golden/performance/backend) |
| Риски | ✅ | §14, 12 строк с вероятностью/impact/mitigation |
| Откат | ✅ | §15 |
| Release-артефакты | ✅ | §13 |
Все обязательные разделы присутствуют и содержательны. Дополнительно
присутствуют продуктовые под-разделы §7.1 (персона/поверхность/момент внутри
§1) и явный блок §16 «принятые технические предположения — можно менять без
пересмотра продукта», корректно отделённый от решений владельца §3.
## Находки
Находок уровня **High** и **Medium** нет.
### Low-1 — отсутствует буквальная декларация «Touch editor: …»
**Файл:** `docs/specs/122-isometric-stage2.md` (весь документ)
`docs/TOUCH-SUPPORT.md` («Documentation rule») требует от новых спецификаций
редакторных фич явно указывать одно из: `Touch editor: supported` / `best
effort / intentionally degraded` / `not exposed`. Предшественник, Stage 1
(`docs/specs/089-isometric-view-stage1.md`, §7 «Touch editor: не exposed»),
эту декларацию давал буквально, хотя ситуация идентична — редакторы Stage 2
не касается вовсе (§6.1 «Editors and houseplan-space-card stay Flat»). Stage 2
такой буквальной строки не содержит, хотя по содержанию §6.1/§6.8 поведение
однозначно совпадает с «not exposed» — реальной неоднозначности для
разработчика или ревьюера кода нет.
**Решение ревьюера:** Low, не блокирует. Формально Stage 2 не вводит новую
редакторную фичу (правило `TOUCH-SUPPORT.md` адресовано именно им), а
содержательно контракт «редакторы не меняются» зафиксирован дважды (§6.1,
§9). Оставляю на усмотрение автора — можно добавить строку `Touch editor: not
exposed` при следующей правке для единообразия с Stage 1, можно снять этой
записью.
### Low-2 — три AC используют тип доказательства вне буквального перечня §2.5
**Файл:** `docs/specs/122-isometric-stage2.md:445-457` (AC13, AC15, AC16)
DoR (`PROCESS.md` §2.5) перечисляет типы доказательства как `unit` / `backend`
/ `smoke` / `golden` / «ревью кода». AC13 помечен только `(performance)`,
AC15 — `(golden + documentation review)`, AC16 — `(typecheck + unit + build)`.
Буквально `performance`, `typecheck`, `build` и `documentation review` в этот
перечень не входят. По существу все три доказуемы существующими механизмами:
`performance_smoke`/Full Performance и `typecheck`/`build` — реальные
release-blocking гейты `PROCESS.md` §8, а «documentation review» — часть
обычного код-ревью (§2.7). Тот же паттерн уже был отмечен как Low-1 в
`SPEC-REVIEW-123-r1` и оставлен автору без блокировки цикла.
**Решение ревьюера:** Low, не блокирует. Переформулировка в термины §2.5 (например,
«ревью кода со ссылкой на `performance_smoke`/exact-SHA Full Performance» и
«ревью кода со ссылкой на зелёный `typecheck`/`test`/`build`») повысила бы
буквальную трассируемость, но не меняет, чем на практике будет доказан
критерий. Оставляю на усмотрение автора или снимаю этой записью.
## Что проверено и корректно
- Соответствие `docs/SCOPE.md`: задача закрывает J1/J2/J3, остаётся внутри
узкого owner-approved исключения (2.5D, не фотореализм/не свободная камера/
не interior editor), не трогает единственную санкционированную поверхность
actuation замков (`docs/SCOPE.md` «The lock invariant»).
- Все вопросы владельцу (Q0–Q6) — продуктовые (видимое поведение, объём
видимых изменений), ни один технический вопрос не был переадресован
владельцу; все ответы получены и внесены в ТЗ без расширения скоупа.
- ТЗ явно наследует, а не переопределяет Stage 1: проекция, `wallBodiesGeometry`,
fingerprint без `_cfgEpoch`/HA-состояния, LRU-кэш 8 сцен, latched flat
fallback, Labs-грамматика `iso`/`1.62.0`/`1.65.0` — все повторно
использованы корректно, ни одно принятое решение Stage 1 не переписывается
задним числом (историческая ADR-89 остаётся неприкосновенной, заводится
новая `docs/adr/122-isometric-stage2-composition.md`).
- Технические утверждения о существующем коде (10° gate, two-leaf window,
static-open default при отсутствии contact, один регион света на источник,
`wallBodiesGeometry` как единственный источник геометрии стен) подтверждены
чтением реального кода, а не приняты на слово автора.
- Скоуп/не-скоуп (§4/§5) корректно отсекает публичный rollout, второй флаг
`iso2`, свободную камеру/#82, новые material-настройки, объёмные редакторы и
`houseplan-space-card`, схемные поля высоты/подоконника, WebGL/Three.js — все
типичные места, где скоуп мог бы незаметно расшириться, явно закрыты.
- Зависимость от #124 обработана корректно: не как продуктовое решение
Q0–Q6 (не переоткрывает их), а как отдельный DoR-блокер реализации (§10) с
двумя явными путями снятия; ревью ТЗ по правилам `PROCESS.md` §10 разрешено
вести, пока #124 открыт.
- i18n/UX (§9): подтверждено отсутствием новых строк, README/CHANGELOG/
USER-GUIDE не обещают публичную функцию — соответствует `User-Visible: no`
контракту для всей будущей реализации.
- Модель данных и совместимость (§8): подтверждено отсутствием новых
схемных полей, ключей `localStorage` версий и compatibility-записей;
откат (§15) не требует миграции и работает немедленно через
`?hp-labs=-iso`/`off`, как и в Stage 1.
- AC1–AC16 однозначны, у каждого указан тип доказательства (за вычетом Low-2)
и план автотестов (§12) даёт конкретный, воспроизводимый по коду маршрут;
§12.1 явно требует, чтобы каждый unit-мутант «умел падать» (удаление
внешнего edge, сдвиг leaf с jamb, включение HA-состояния в cache key,
дублирование floor symbol, лишний light layer).
- Не найдено ни одного продуктового утверждения о поведении, которое не
следует ни из канонических документов, ни из решений владельца Q0–Q6, ни
из чтения существующего кода, и при этом не помечено как предположение;
раздел §16 корректно отделяет свободно изменяемые технические детали
(именование модулей, точные проценты высоты панелей, число SVG-корней) от
зафиксированных владельцем решений.
- Реестр `docs/specs/README.md` обновлён тем же коммитом, коммит несёт
корректные трейлеры (`Issue: #122`, `User-Visible: no`) и не содержит
изменений класса A — правило №1 соблюдено на этапе `spec`.
## Чего не проверял
- Не проверял реализуемость конкретной геометрической декомпозиции
(`iso-openings.ts`/`iso-scene.ts`, точные проценты высоты панелей, число
SVG-defs) — по правилам ТЗ (§16) это свободно изменяемое техническое
предположение автора кода, не предмет ревью ТЗ.
- Не проверял реальный performance-профиль `large-house-isometric-v1` и не
прогонял #124 — на этапе `spec` это не требуется; факт открытости и
статус #124 (`S1-new`) проверен через `gh issue view`, не исполнением
бенчмарка.
- Не запускал никаких автотестов, golden или смоков — на этапе `spec` это не
требуется; существование референсных артефактов (`isometric-no-borders-dark`
в `demo/golden/matrix.mjs`) проверено чтением файла, не исполнением.
- Не проверял содержимое `docs/adr/089-isometric-stage1-renderer.md` построчно
на полное покрытие всех констант камеры — доверился ссылке ТЗ и
`docs/ISOMETRIC.md` как согласованному пересказу; расхождений при чтении
обоих источников не обнаружено.
- Не оценивал субъективную эстетическую адекватность референсов владельца
(issue #89, комментарий с изображениями) — это продуктовое решение,
принятое владельцем через Q2 и не подлежащее пересмотру ревьюером ТЗ.
## Вердикт
Зелёный. High: 0, Medium: 0. Две находки Low (отсутствие буквальной
декларации `Touch editor: …` и три AC с типом доказательства вне буквального
перечня §2.5) — не блокируют, оставлены автору на усмотрение с записью в этом
документе; при желании их можно поправить в этом же цикле без возврата в
`S3-spec`.