mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-07 15:09:30 +00:00
@@ -0,0 +1,185 @@
|
||||
# SPEC-REVIEW-242-r1
|
||||
|
||||
- Issue: [#242](https://github.com/Matysh/houseplan-card/issues/242) — «Проём в толстой стене рисуется у произвольной грани, а не по центру толщины»
|
||||
- Этап: ТЗ на ревью (PROCESS.md §2.4)
|
||||
- Артефакт ТЗ: `docs/specs/242-opening-symbol-center.md`, ревизия `0033138`
|
||||
- Ветка: `issue/242-opening-symbol-center`
|
||||
- Заход: **r1**, блокирующих циклов израсходовано **0 из 4** (лимит обычного трека — 4, §4)
|
||||
- Вердикт: **зелёный**
|
||||
|
||||
## Скоуп ревью
|
||||
|
||||
Первый заход — полный разбор ТЗ, без ограничения по дельте (§2.10 применяется
|
||||
только со второго захода).
|
||||
|
||||
Проверялось:
|
||||
|
||||
1. Соответствие обязательным разделам §7.1 PROCESS.md.
|
||||
2. Продуктовая рамка — принадлежность задачи job'ам из `docs/SCOPE.md`.
|
||||
3. Верность диагноза — сверка цитируемого кода с текущим `HEAD` (та же
|
||||
ревизия, на которой ТЗ написано).
|
||||
4. Проверяемость и однозначность AC1…AC8.
|
||||
5. Отсутствие догадок, выданных за факт (решения без пометки, что это
|
||||
предположение автора, а не решение владельца).
|
||||
6. Совпадение зафиксированных в ТЗ product-решений (§4) с ответами владельца в
|
||||
комментариях issue (Q1–Q4).
|
||||
7. Техническая осуществимость геометрического контракта (§7 ТЗ) — не
|
||||
декларация ли это того, что текущая модель данных не может обеспечить.
|
||||
8. Термины интерфейса — сверка с `docs/USER-GUIDE.ru.md`, а не изобретённые.
|
||||
9. Полнота списка канонических документов, которые придётся обновить.
|
||||
|
||||
## Как проверялось
|
||||
|
||||
- Прочитаны `docs/SCOPE.md`, `AGENTS.md`, `PROCESS.md`, тело issue #242 и все
|
||||
5 комментариев (аналитика → занятие → вопросы владельцу → решения владельца
|
||||
→ готовое ТЗ).
|
||||
- Прочитан `docs/specs/242-opening-symbol-center.md` целиком.
|
||||
- Прочитаны канонические `docs/WALL-THICKNESS.md` и `docs/ISOMETRIC.md`.
|
||||
- В `docs/USER-GUIDE.ru.md` найден и прочитан раздел «Толстые стены»
|
||||
(строки 606–616) и таблица «Настройки проёма» (568–575) — источник
|
||||
интерфейсной терминологии, которую ТЗ обязано использовать без изменений.
|
||||
- Прочитан код, на который ссылается диагноз ТЗ, чтобы отделить проверенный
|
||||
факт от догадки:
|
||||
- `src/wall-thickness.ts` — `OpeningWallSide`, `resolveOpeningWallAssociation`,
|
||||
`openingInnerFaceOffsetFromIndex` (строки ~2340–2530);
|
||||
- `src/partition-openings.ts` — `partitionOpeningFace` (153–165);
|
||||
- `src/render/opening-symbol.ts` — `openingVisibleMetrics`,
|
||||
`renderOpeningVisibleGeometry` (1–147);
|
||||
- `src/houseplan-card.ts` — рендер `op-hit`/`op-outline` (18530–18588) и
|
||||
позиционирование lock-бейджа (18590–18618).
|
||||
- Продуктовый код и ТЗ не редактировались — ревьюер только читает.
|
||||
|
||||
Гейты для этапа ТЗ не запускались: PROCESS.md §8 требует их на код-ревью, а
|
||||
здесь нет ни строчки кода. Автор уже отчитался о `node scripts/check-docs.mjs`
|
||||
для diff'а этого захода (только `docs/specs/**`), что достаточно для этой
|
||||
стадии.
|
||||
|
||||
## Находки
|
||||
|
||||
Нет. Ни одной High, Medium или Low.
|
||||
|
||||
## Что проверено и признано корректным
|
||||
|
||||
**Структура ТЗ (§7.1).** Все обязательные разделы на месте: сценарий и
|
||||
персона (§1), что человек увидит до/после (§2), диагноз/проблема (§3),
|
||||
скоуп и не-скоуп (§6), контракт поведения (§7–8), данные/миграция/i18n/a11y/
|
||||
touch (§9), перф и безопасность (§10), AC1…AC8 с доказательством (§11), план
|
||||
автотестов (§12), mutation guards (§13), гейты (§14), release-артефакты
|
||||
(§15), откат (§16), риски (§17), явный блок принятых технических
|
||||
предположений (§18). Ничего не подменяет продуктовый вопрос техническим и
|
||||
наоборот.
|
||||
|
||||
**Продуктовая рамка.** Задача закрывает J4 («от нуля до плана без внешнего
|
||||
редактора» — точность геометрии) и J6 («план остаётся достоверным при
|
||||
эволюции комнат» — независимость от порядка `space.rooms`); во View
|
||||
дополнительно поддерживает J1 (одинаковое чтение геометрии независимо от
|
||||
внутреннего порядка данных), как и написано в аналитике issue. Ни одна
|
||||
строка `docs/SCOPE.md` не нарушается, новых поверхностей продукта не
|
||||
добавляется.
|
||||
|
||||
**Диагноз подтверждён чтением, а не поверил автору на слово.** Прочитанный
|
||||
код на актуальном `HEAD` (`0033138`, тот же коммит, на котором писалось ТЗ)
|
||||
подтверждает каждое утверждение §3 ТЗ:
|
||||
- `openingInnerFaceOffsetFromIndex` действительно сортирует кандидатов по
|
||||
`order` — полю, комментарий к которому в коде прямо называет его
|
||||
«first matching room edge in config order» (wall-thickness.ts:2355) — и
|
||||
берёт `available[0]` как «natural» грань (2513–2520);
|
||||
- `partitionOpeningFace` действительно фиксирует знак `side` от `flipV` и
|
||||
умножает его на `resolved.axis` — направление, которое зависит от того, как
|
||||
сохранены `partition.a`/`partition.b` (partition-openings.ts:157–164);
|
||||
- `renderOpeningVisibleGeometry` переносит только группу `body` (дуга/створки/
|
||||
стекло) через `translate(swingTx swingTy)` (opening-symbol.ts:74–137);
|
||||
косяки (`op-jamb`-линии на `±half` — здесь и далее «half» это `jambHalf`,
|
||||
то есть половина физической толщины) рисуются вне этой группы (140–146) —
|
||||
то есть **уже сейчас** структурно независимы от face-сдвига. Это прямо
|
||||
подтверждает пункт контракта ТЗ §7 «Косяки всегда остаются на `±cm/2` … и
|
||||
не входят в translated группу» — не предположение, а описание уже
|
||||
существующей структуры кода, которую нужно не разрушить, а сохранить.
|
||||
|
||||
**Геометрический контракт (§7 ТЗ) реализуем на текущей модели данных**, а не
|
||||
декларация невозможного:
|
||||
- Для стены комнаты `side` (`-1`/`1`) уже вычисляется из `opening.angle` через
|
||||
`nx = -sin(rad), ny = cos(rad)` и знака `inward`-нормали ребра
|
||||
(wall-thickness.ts:2419–2441) — это уже канонический локальный базис самого
|
||||
проёма, **не зависящий от `order`**. Order используется только для выбора,
|
||||
какая из двух сторон общей стены становится «natural» (unflipped) —
|
||||
единственное, что требует замены на фиксированное правило по локальной оси.
|
||||
Никакой новой геометрической информации придумывать не нужно.
|
||||
- Для partition та же независимая от направления рисования величина уже
|
||||
доступна — тот же `opening.angle`, что и для room-wall (сейчас не
|
||||
используется в `partitionOpeningFace`, но используется параллельно для
|
||||
room-wall face). Перевести partition-резолвер на тот же базис, вместо
|
||||
`resolved.axis`, зависящего от `a`/`b`, технически прямолинейно.
|
||||
- **Lock-бейдж переживёт правку без отдельного контракта**, хотя ТЗ (§18.3)
|
||||
формулирует это как «принятое предположение»: `_renderOpeningLocks`
|
||||
(houseplan-card.ts:18605–18616) вычисляет офсет бейджа как
|
||||
`lockOffset * sign`, где `lockOffset` — фиксированная величина в grid units,
|
||||
**не связанная с `face.ox/oy`/`cm`** вообще; она использует только знак
|
||||
(`gateFace.side` либо `flip_v ? -1 : 1`). Смена перевода видимой группы с
|
||||
«сдвиг на грань» на «центр» этот знак не меняет ни для одного из
|
||||
зафиксированных в контракте случаев (§7 ТЗ) — прочитано и проверено
|
||||
чтением, вывод сильнее, чем у самого автора: это не предположение,
|
||||
которое ревьюер не оспорил, а проверенный факт.
|
||||
|
||||
**Верность отражения решений владельца.** Раздел §4 ТЗ построчно совпадает с
|
||||
ответами владельца из комментария `2026-08-22T17:07:08Z` на все четыре вопроса
|
||||
(Q1 flip_v-совместимость, Q2 направление ворот, Q3 parity поверхностей, Q4
|
||||
окно целиком) — без искажений и без добавления нового необсуждённого
|
||||
поведения. Технические детали (§18: формула локальной оси, имя типа
|
||||
visual-offset) явно помечены как «принято предположительно, менять свободно»
|
||||
и не выданы за продуктовое решение.
|
||||
|
||||
**Проверяемость AC.** Все восемь AC (§11) сформулированы через числа и
|
||||
конкретные наблюдаемые свойства (нулевое смещение, идентичность метрик при
|
||||
перестановке, сохранение full-depth jambs, отсутствие diff в schema), а не
|
||||
через «выглядит по центру» — ровно то, что требует сама постановка issue
|
||||
(«AC стоит формулировать через числа»). У каждого указан способ доказательства
|
||||
в допустимом словаре (`unit`/`smoke`/`golden`/`review`).
|
||||
|
||||
**Терминология.** «Открывается в другую сторону» и «flip_v» использованы как
|
||||
в `docs/USER-GUIDE.ru.md` (568–575), без изобретения нового языка. ТЗ явно
|
||||
называет тот самый абзац «Толстые стены» (606–616) устаревшим фактическим
|
||||
описанием («Створка/дуга двери и окна смещается к внутренней грани комнаты, а
|
||||
створки ворот — к наружной») и относит его обновление к release-артефактам
|
||||
своего user-visible коммита (§15) — список канонических документов на
|
||||
обновление (`USER-GUIDE.ru.md`, `WALL-THICKNESS.md`, `ARCHITECTURE.md`,
|
||||
`ISOMETRIC.md`, changelog RU+EN) полон, ничего из задетых поверхностей не
|
||||
забыто.
|
||||
|
||||
**Не-скоуп обоснован.** Passage (нет видимого символа), wall cut/jamb depth/
|
||||
opening length, lock badge, hitbox, Glow/sun/decor/vacuum, новый Iso UX или
|
||||
config-migration — всё это корректно исключено и не пересекается с
|
||||
задекларированным контрактом §7–8.
|
||||
|
||||
## Чего не проверял
|
||||
|
||||
- **Не запускал автотесты/гейты** — на этапе ТЗ кода нет, гейты §8
|
||||
относятся к код-ревью.
|
||||
- **Не проверял `docs/ARCHITECTURE.md` целиком** — только убедился, что файл
|
||||
фигурирует как канонический для этого изменения и включён в release-
|
||||
артефакты §15; содержимое самого файла не читал, это не требуется для
|
||||
вывода о полноте ТЗ.
|
||||
- **Не оценивал `docs/specs/README.md` рассинхрон колонки «Статус ТЗ»**
|
||||
(известный открытый пункт PROCESS.md §7.3.1, не относится к #242) — запись
|
||||
строки #242 в таблице P2 корректна и не мой предмет.
|
||||
- **Не проверял `iso-openings.ts`/`buildIsoOpeningBasis()` построчно** —
|
||||
прочитал только его роль по `docs/ISOMETRIC.md` («door has one jamb-hinged
|
||||
leaf… mirrors the existing opening-symbol transform algebra»); ТЗ верно
|
||||
определяет его как одну из четырёх поверхностей parity (AC5), детальную
|
||||
реализуемость там не проверял глубже необходимого для вывода «этот
|
||||
контракт возможен» — она подтверждена уже на room-wall/partition пути, а
|
||||
Iso по документации использует ту же алгебру.
|
||||
- **Не проверял mutation-gate script и наличие тестовых фикстур** — на этапе
|
||||
ТЗ они не существуют, это работа код-ревью.
|
||||
- Никаких browser-smoke/golden не запускал — на этапе ТЗ нет рендера для
|
||||
сравнения.
|
||||
|
||||
## Заключение
|
||||
|
||||
ТЗ полно по составу разделов, продуктово обосновано, верно отражает решения
|
||||
владельца без домыслов, а диагноз и предложенный контракт подтверждены
|
||||
чтением актуального кода (в том числе в пунктах, которые сам автор пометил
|
||||
как непроверенное предположение — lock-бейдж, независимость косяков). High/
|
||||
Medium-находок нет. Задача может двигаться в `S5-ready`.
|
||||
|
||||
**Вердикт: зелёный · заход r1 · блокирующих циклов 0/4 · High: 0 · Medium: 0 → в задаче**
|
||||
Reference in New Issue
Block a user