mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-30 11:49:16 +00:00
@@ -0,0 +1,194 @@
|
||||
# SPEC-REVIEW-229-r3
|
||||
|
||||
- **Issue:** https://github.com/Matysh/houseplan-card/issues/229
|
||||
- **ТЗ:** `docs/specs/229-merge-collinear-partitions.md`
|
||||
- **SHA на момент этого ревью:** `1ecd26713882e11760daed80003632d7e8778ba2`
|
||||
(коммит `docs: a room junction is a side, not just a corner (#229 r2 M1)`)
|
||||
- **Этап:** spec (PROCESS.md §2.4) · трек: обычный (не `small`)
|
||||
- **Заход:** r3 · блокирующих циклов израсходовано 2/4 до этого вердикта
|
||||
- **Предыдущие раунды:**
|
||||
- `docs/reviews/SPEC-REVIEW-229-r1.md`, вердикт жёлтый, SHA `81210f7afc1995b52c031daa1f593f1b54e03f8f`
|
||||
- `docs/reviews/SPEC-REVIEW-229-r2.md`, вердикт жёлтый, SHA `ecc3d6a88ba259d3446f77ab3a60170337bc068f`
|
||||
- **Ревьюер:** Claude, роль «ревьюер ТЗ»
|
||||
|
||||
## Скоуп этого раунда
|
||||
|
||||
Дельта — ровно один коммит, `1ecd267`, отвечающий на единственную находку r2
|
||||
(Medium-1: «ребро комнаты» в §8.2 определено как «ближайшая вершина полигона», а
|
||||
не как отрезок, из-за чего T-стык партиции к середине комнатной стены не
|
||||
считался бы причиной оставить узел). Правка трогает только
|
||||
`docs/specs/229-merge-collinear-partitions.md`: один абзац §8.2, формулировку
|
||||
AC2, одну новую строку мутационного гейта (§14). Тело issue #229 не менялось
|
||||
(сверено с `gh issue view 229` — последний комментарий автора и есть хендофф
|
||||
r2→r3, без изменения текста issue). Метка issue сейчас `S4-spec-review`, без
|
||||
`small`/`review-4`, что подтверждает регулярный трек и лимит 4 циклов.
|
||||
|
||||
Дельта локальна (§2.10 PROCESS.md): один коммит, одна секция плюс точечная
|
||||
правка соседних, не ребейз, не смена контракта, не новая подсистема — объём
|
||||
разбора сокращён до находки r2 и того, что она затрагивает (§8.2, AC2, §14);
|
||||
остальное наследуется из r1/r2 без повторного прогона.
|
||||
|
||||
## Как проверялось
|
||||
|
||||
1. Прочитан вердикт r2 (`docs/reviews/SPEC-REVIEW-229-r2.md`) целиком — одна
|
||||
Medium-находка (Medium-1), без High.
|
||||
2. `git diff ecc3d6a..HEAD -- docs/specs/229-merge-collinear-partitions.md` —
|
||||
единственный файл дельты, 18 строк; построчно сверен с требованием
|
||||
Medium-1 из r2 («что нужно»: заменить «ближайшая вершина полигона» на
|
||||
«ближайшая точка на любой стороне (ребре) полигона»).
|
||||
3. Прочитан комментарий автора в issue (хендофф r2→r3, `2026-08-21T08:56:11Z`)
|
||||
— сверен с фактическим диффом, а не принят на слово: текст диффа совпадает
|
||||
с тем, что автор описывает.
|
||||
4. Проверены обе фактические ссылки, добавленные правкой:
|
||||
- `docs/specs/141-wall-junctions.md` — новый абзац §8.2 цитирует «§13.1» с
|
||||
фразой «к середине существующей wall/partition». Прочитан весь файл
|
||||
141 вокруг §4, §13.1 и §13.2 построчно: искомая фраза находится не в
|
||||
§13.1 (строки 332–349, п.5 — «T partition→partition, draft→partition и
|
||||
partition→solid room wall», без слова «середина»), а в **§13.2**, п.3
|
||||
(строка 361: «...новую partition через line-snap #137 к середине
|
||||
существующей wall/partition»). Правильный якорь для утверждения «T-стык
|
||||
к комнатной стене — штатный случай продукта» — это §4.1 (строка 60–62:
|
||||
«endpoint↔line (T) соединения... между active/saved draft, partition и
|
||||
готовой комнатной стеной») и §13.1 п.5, которые сам ревьюер верно
|
||||
процитировал в r2. Разбор — находка этого раунда, см. ниже.
|
||||
- `src/plan-snap-overlay.ts:313` — прочитан файл целиком в окрестности
|
||||
строки; `distToSegment([pointer[0], pointer[1]], line)` на строке 313
|
||||
точно совпадает, и `line` строится из `geometry.segments`, которые
|
||||
(строка 139) заполняются из `roomEdges(options.space.rooms)` —
|
||||
подтверждено чтением `src/logic.ts` (`roomEdges`, `distToSegment`,
|
||||
строки 134 и 1937). Примитив «расстояние точки до стороны комнаты»
|
||||
действительно существует и действительно оперирует отрезком, а не
|
||||
вершиной — ссылка точна.
|
||||
5. Заново прочитаны §8.2, AC2 (§12) и новая строка §14 — единственные места,
|
||||
которые дельта задевает. Проверено, что формулировка AC2 после правки
|
||||
требует теста именно на T-стык в середину длинного ребра, а не только на
|
||||
угол, и что новый мутант (`junction-checks-room-vertices-only`) откатывает
|
||||
ровно эту правку («искать примыкание комнаты только по вершинам
|
||||
полигона») — то есть гейт умеет отличить старое (неверное) поведение от
|
||||
нового.
|
||||
6. Не перечитывались повторно: §1–§7, §9, §10, §11, §15, §16, §17, AC1, AC3–AC9
|
||||
— дельта их не касается (см. «Унаследовано» ниже).
|
||||
7. Код не запускался, гейты не гонялись — на этапе spec-review реализации нет
|
||||
(как в r1 и r2).
|
||||
|
||||
## Закрытие раунда r2
|
||||
|
||||
| Находка r2 | Чем закрыта | Где это видно |
|
||||
|---|---|---|
|
||||
| **Medium-1** — критерий «ребро комнаты» (§8.2) требовал совпадения с **ближайшей вершиной** полигона, что пропускало T-стык партиции к середине комнатной стены — канонический случай `docs/specs/141-wall-junctions.md` §4.1/§13.1 п.5 | §8.2 переписан: «Точка стыка берётся у ребра комнаты — **ближайшая точка на любой стороне полигона**, а не только его вершина». Добавлен поясняющий абзац со ссылкой на канон и на существующий код-примитив `distToSegment`/`roomEdges`. AC2 дополнен требованием: случай «ребро комнаты» доказывается T-стыком в середину длинного ребра, тест обязан быть красным, если реализация ищет только вершины. В §14 добавлен мутант `junction-checks-room-vertices-only` → guard «юнит AC2 (T-стык)» | `docs/specs/229-merge-collinear-partitions.md` §8.2 (абзацы 1–2 после правки), §12 AC2 (предложение о T-стыке), §14 (новая строка таблицы) |
|
||||
|
||||
Закрыта полностью и по существу: формулировка §8.2 теперь point-to-segment, а
|
||||
не point-to-vertex, ровно то, что требовало «что нужно» в r2. AC2 после правки
|
||||
не найдёт причину оставить узел только по критерию, который сам же и
|
||||
пропускал T-стык — наоборот, AC2 явно требует падения теста на этом сценарии
|
||||
до фикса и держит его зелёным после.
|
||||
|
||||
## Находки этого раунда
|
||||
|
||||
### Low-1 — новый абзац §8.2 цитирует §13.1 фразой, которая на самом деле находится в §13.2
|
||||
|
||||
**Файл:** `docs/specs/229-merge-collinear-partitions.md`, §8.2, второй абзац
|
||||
(внесён дельтой r3).
|
||||
|
||||
**Формулировка ТЗ:** «...штатный случай продукта (`docs/specs/141-wall-junctions.md`
|
||||
§13.1 прямо называет примыкание «к середине существующей wall/partition»)...»
|
||||
|
||||
**Проблема.** Фраза «к середине существующей wall/partition» находится в
|
||||
`docs/specs/141-wall-junctions.md` строка 361, это пункт 3 раздела **§13.2**
|
||||
(«Targeted production-bundle smoke» — сценарий рисования новой перегородки
|
||||
через line-snap #137 к середине существующей стены), а не §13.1 («Unit» —
|
||||
пункт 5 там говорит «T partition→partition, draft→partition и
|
||||
partition→solid room wall», без слова «середина»). Утверждение по существу
|
||||
верное и подтверждённое документом — T-стык партиции к комнатной стене
|
||||
действительно канонический случай продукта, — но подтверждается оно §4.1
|
||||
(строка 60–62, «endpoint↔line (T)... между... partition и готовой комнатной
|
||||
стеной») и §13.1 п.5, а не тем местом, которое сейчас названо. Сам ревьюер
|
||||
процитировал верные места (§4.1 и §13.1 п.5) в r2 — здесь автор ТЗ, судя по
|
||||
всему, взял идею оттуда, но перепутал номер подраздела и вставил не ту цитату.
|
||||
|
||||
**Почему это не блокирует.** AC2 (§12) самодостаточен: он требует конкретного
|
||||
теста («T-стык в середину длинного ребра», красный при поиске только вершин)
|
||||
и не зависит от того, на какой подраздел ссылается пояснительный абзац.
|
||||
Утверждение при этом не голая догадка без подтверждения — оно подтверждено в
|
||||
том же документе, только другим номером параграфа; я independently
|
||||
перечитал §4.1 и §13.1 весь файл 141 и убедился, что канон действительно
|
||||
требует T-стыка partition↔room-wall. Ревьюер кода не будет ориентироваться на
|
||||
номер параграфа — он будет писать unit-тест по буквальному требованию AC2.
|
||||
|
||||
**Решение.** Снимаю без действия автора: заменить «§13.1» на «§4.1» (или на
|
||||
«§13.1 п.5 и §4.1») можно одной правкой при следующей любой правке этого
|
||||
файла, но отдельного цикла ревью это не стоит — ни AC, ни контракт не
|
||||
затронуты, эффект чисто в точности сноски.
|
||||
|
||||
## Унаследовано из r1/r2 (без повторной проверки)
|
||||
|
||||
Документы: `docs/reviews/SPEC-REVIEW-229-r1.md` (SHA `81210f7`),
|
||||
`docs/reviews/SPEC-REVIEW-229-r2.md` (SHA `ecc3d6a`). Принято на веру, так как
|
||||
дельта r3 этих мест не касается:
|
||||
|
||||
- Продуктовая рамка §1–§4 (персона, сценарий, три решения владельца
|
||||
2026-08-21) — не менялась с r1; тело issue не менялось между r2 и r3
|
||||
(сверено в этом раунде).
|
||||
- §5–§7 (цели, скоуп, не-скоуп), §9 (данные/i18n/a11y), §10 (performance), §15
|
||||
(release-артефакты), §16 (откат) — не менялись дельтой r3, r2 их тоже не
|
||||
трогал.
|
||||
- §8.6 («Что именно сращивается при завершении цепочки», закрытие M1 из r1) и
|
||||
AC8 — проверены r2, дельта r3 их не касается.
|
||||
- §8.4 (материализация `x/y/angle`, закрытие M3 из r1) и AC3 — проверены r2,
|
||||
дельта r3 их не касается.
|
||||
- AC1, AC4, AC5, AC6, AC7, AC9 — признаны однозначными и проверяемыми в r1,
|
||||
формулировки не менялись ни в r2, ни в r3.
|
||||
- Соответствие обязательным разделам §7.1 PROCESS.md, отсутствие непомеченных
|
||||
догадок за пределами §8.2/§8.4/§8.6 (кроме разобранной здесь мелкой находки)
|
||||
и корректность `Touch editor: not exposed` по `docs/TOUCH-SUPPORT.md` §153 —
|
||||
проверены в r1, не переоценивались.
|
||||
- Строки кода `wall-thickness.ts:1258`, `plan-optimizer.ts:402-530`,
|
||||
`align-grid.ts:262`, `partition-openings.ts:43-90`, `wall-thickness.ts:743`,
|
||||
`:2256`, `houseplan-card.ts:6538`, `:7824`, `:12007`, проверенные в r1/r2, —
|
||||
дельтой r3 не менялись, не перечитывались повторно.
|
||||
- Согласованность с `docs/USER-GUIDE.ru.md` §8 — не переоценивалась, дельта её
|
||||
не касается.
|
||||
- «Чего не проверял» из r2 (значения `EPS_ANGLE`/`EPS_JOIN` как числа —
|
||||
осознанно не зафиксированы; критерий «колонна — центр» — не подтверждён и не
|
||||
опровергнут, останется открытым до код-ревью) — остаётся в той же
|
||||
формулировке, дельта r3 этого не касается.
|
||||
|
||||
## Что проверено и корректно (дельта r3)
|
||||
|
||||
- Medium-1 из r2 закрыта по существу текстом ТЗ (не заявлением автора) — см.
|
||||
таблицу закрытия выше. Формулировка §8.2 теперь point-to-segment, ровно то,
|
||||
что было запрошено.
|
||||
- AC2 после правки требует падения теста на T-стыке в середину ребра при
|
||||
реализации, ищущей только вершины — дисциплина «тест должен уметь падать»
|
||||
сохранена.
|
||||
- Новая строка мутационного гейта (`junction-checks-room-vertices-only`)
|
||||
корректно привязана к AC2 и откатывает именно правку этого раунда.
|
||||
- Ссылка на код `plan-snap-overlay.ts:313` точна и подтверждена чтением файла
|
||||
и `src/logic.ts` (`roomEdges`, `distToSegment`) — примитив «точка-к-отрезку»
|
||||
для рёбер комнаты действительно существует в кодовой базе.
|
||||
- Продуктовая рамка не расширена и не сужена этой правкой: изменение чисто
|
||||
геометрическое (точка стыка — отрезок, а не вершина), пользователь не видит
|
||||
разницы между «стык у угла» и «стык посередине стены», оба должны одинаково
|
||||
сохранять узел — не продуктовый вопрос, решён ревьюером r2 по инструкции.
|
||||
|
||||
## Чего не проверял
|
||||
|
||||
- Реализацию — её не существует на этом этапе.
|
||||
- Продуктовую рамку и решения владельца §1–§4, §8.4, §8.6, AC1, AC3–AC9 — не
|
||||
менялись дельтой, наследуются из r1/r2 (см. выше).
|
||||
- Существующие смоки и `docs/specs/README.md` — вне зоны этого ревью и не
|
||||
затронуты дельтой, как и в r1/r2.
|
||||
- Критерий «колонна — центр» — остаётся открытым предположением из r2, дельта
|
||||
r3 его не касается, всплывёт на код-ревью через AC2, если окажется неверным.
|
||||
- Точный номер параграфа в `docs/specs/141-wall-junctions.md`, куда стоило бы
|
||||
переставить цитату (см. Low-1) — снято решением ревьюера без требования
|
||||
правки, дальше не разбиралось.
|
||||
|
||||
## Вердикт
|
||||
|
||||
Единственная находка предыдущего раунда (Medium-1) закрыта полностью и по
|
||||
существу текстом ТЗ, а не заявлением автора. Единственная новая находка этого
|
||||
раунда — Low (неверный номер подраздела в пояснительной ссылке, без влияния на
|
||||
AC или контракт) — снимаю с записью, без возврата на правку. High нет, Medium
|
||||
в скоупе нет. Итог — **зелёный**: ТЗ готово к разработке (`S5-ready`).
|
||||
Зелёный вердикт бюджет циклов не тратит (§4, #227) — израсходовано 2/4.
|
||||
Reference in New Issue
Block a user