13 KiB
SPEC-REVIEW-228-r1
- Issue: #228 — «Проблемы при рисовании плана»
- Этап: spec (PROCESS.md §2.4)
- Заход: r1 · блокирующих циклов израсходовано 0/4
- ТЗ:
docs/specs/228-plan-drawing-problems.md, коммитdca4ed2, веткаissue/228-plan-drawing-problems, HEAD совпадает с этим коммитом - Вердикт: зелёный
Скоуп
Задача объединяет шесть наблюдений владельца по инструменту «Стены»: (1)
отсутствие оси/узла на активном отрезке, (2) зубцы на углах из-за неверного
snap, (3) ложное «незамкнутая комната» при разрывах ≤ несколько см, (4)
диалог удаления комнаты не спрашивает про стены, (5) невозможность создать
комнату из готового замкнутого контура, (6) Shift не даёт строгого угла
после snap, а подпись остаётся зелёной при 90,1°. Owner подтвердил на 2026-08-19
(issue #227) правило бюджета циклов и держит все шесть пунктов в одной задаче
(закрывает J4/J6, docs/SCOPE.md).
Это первый заход — прежнего вердикта нет, деление на дельту (§2.10) не применяется, разбор полный.
Как проверялось
- Прочитаны
docs/SCOPE.md,AGENTS.md,PROCESS.md(§1–§4, §7.1, §7.2, §12), тело issue #228 и все 4 комментария (аналитика, продуктовые вопросы с defaults, решения владельца, хендофф «ТЗ готово»). - Прочитаны канонические документы подсистемы:
docs/CANVAS.md(разделы «Architectural connection overlay», «Planar wall faces», §9 snap/Shift),docs/WALL-THICKNESS.md(модель partitions/openings, диапазонcm1–100),docs/TOUCH-SUPPORT.md(контракт деградации),docs/USER-GUIDE.ru.md(терминология «Стены», «независимая стена», «проём»). - Каждое фактическое утверждение раздела 3 ТЗ («подтверждённое текущее
состояние») сверено построчно с актуальным кодом на HEAD:
.pathline/.vertexстроятся изpath(houseplan-card.ts:18658,:18664),previewD/previewPtsвключают курсор (:18497–18519) — подтверждает пункт 1 (нет оси/узла на активном конце);_resolvePlanDrawPoint(houseplan-card.ts:6752–6772):lock45используется только в веткеthis._snapDrawPoint(raw, lock45), при наличииcandidateвозвращается[...candidate.point]безусловно — подтверждает пункт 6 дословно;is45(deg, tol = 0.5)(logic.ts:1931) — подтверждает вторую половину пункта 6 (широкий допуск красит 90,1° зелёным);_deleteRoomClick(houseplan-card.ts:10898): нативныйconfirm(),sp.rooms = sp.rooms.filter(...)без материализации эксклюзивных стен — подтверждает пункт 4;wall-face-graph.ts:DEFAULT_EPSILON = 0.001,findNewWallFacesищет только грани, появившиеся «by one accepted source segment» — подтверждает пункты 2/3/5 (малый geometry epsilon, контракт #173 не меняется). Все шесть утверждений подтвердились точно, ни одной неверной или додуманной ссылки не найдено.
- Проверено существование и содержание связанных issue: #137 (closed, узлы привязки при рисовании), #141 (closed, зубцы стыков перегородок), #173 (closed, единый инструмент стен → предложение комнаты), #232 (open, S1-new, подсветка оси под курсором) — все ссылки в ТЗ корректны и не переписывают чужой контракт сверх заявленных точек расширения.
- Проверена терминология: «независимая стена» (
USER-GUIDE.ru.md:492), «проём» (:59), «Стены» (:326) — используются в ТЗ так же, как в пользовательском гайде, ничего не изобретено. - Проверено, что
hp-dialogс кнопками.btn.danger/.btn.ghostуже существует как паттерн (например,_renderDecorEraseConfirm,houseplan-card.ts:10237–10249) — предложение §8.7 (primary/danger/Cancel) не вводит новый визуальный язык, а расширяет существующий на одну кнопку. - Проверен фикстур-профиль AC15: «60-room/60-partition» дословно совпадает
с каноническим
npm run benchmark:large-house(docs/TESTING.md:1560, 60 комнат/60 partitions/200 устройств/100 проёмов) — не выдуманное число. - Проверены обязательные разделы ТЗ по PROCESS.md §7.1: сценарий (§1) · что человек увидит (§2) · проблема (§3) · скоуп/не-скоуп (§5/§6) · контракт поведения (§7/§8) · UX (§8) · модель данных и миграция (§9/§10) · i18n (§11.1) · AC1…AC17 с методом доказательства (§13) · план автотестов (§14) · риски (§18) · откат (§19) · release-артефакты (§17). Все на месте.
- Проверено, что раздел 20 («принятые технические предположения») содержит только технические решения (пороги, приоритет tie-break, переиспользование внутренних API) — ни одно не меняет то, что видит или делает пользователь сверх уже утверждённых владельцем 5 defaults.
git show dca4ed2 -- docs/specs/228-plan-drawing-problems.md | git diff --check— чисто. Трейлеры коммита:Issue: #228,User-Visible: no— корректно для чисто документационного изменения (класс C, докстадия).docs/specs/README.mdобновлён линком на файл.
Находки
Блокирующих (High) находок нет. Находок уровня Medium нет.
Одно наблюдение уровня Low, не требующее правки:
- §8.5 описывает 7 шагов для случая «клик внутри существующей грани», но не
проговаривает явно «иначе — обычное начало новой цепочки»; это читается
по контексту (
docs/CANVAS.md, действующее поведение инструмента «Стены» не отменяется, редефинируется только ветка «клик внутри готовой пустой области»), и AC5 отдельно фиксирует, что snap-zone click рисует стену, occupied/duplicate/partial face не предлагаются. Реального риска неоднозначной реализации не вижу — оставляю без правки.
Что проверено и корректно
- Все шесть исходных наблюдений владельца покрыты сценарием/AC один в один (см. таблицу соответствия ниже), без тихих пропусков.
- Все пять продуктовых решений владельца (Q1–Q5, комментарий «Решения владельца») дословно перенесены в §4 и раскрыты в UX-контракте §8.2–§8.7, без переинтерпретации.
- Ambiguity/2-см-repair/удаление комнаты — везде явно описаны инварианты
«no mutation on hover», «fail-closed», «один Undo», совпадающие с
§7 «Инварианты» и не противоречащие
docs/CANVAS.md/WALL-THICKNESS.md. - Non-scope (§6) корректно исключает смежные контракты (#141, #173, #232, toolbar #148, глобальное выравнивание, touch-паритет) — никакого расползания скоупа.
- Touch-раздел (§11.3) использует ровно одну из трёх канонических формул
docs/TOUCH-SUPPORT.md(«best effort / intentionally degraded») и соблюдает safety floor (никакой мутации на pinch/pointercancel/suppressed tap — то же самое требует AC14). - Compatibility (§10): новых persisted полей нет, диапазон
cm1–100 для partitions соответствуетWALL-THICKNESS.md§9, откат (§19) — простой revert коммита без обратной миграции данных. - Release-артефакты (§17) перечисляют оба changelog, все канонические документы подсистемы и три копии бандла — соответствует §2.5 DoR.
- Ни одной догадки, выданной за факт: все утверждения о текущем поведении либо процитированы с номером строки и подтверждены чтением кода, либо явно помечены в §20 как «принято предположительно, поменять свободно».
Таблица соответствия наблюдение → decision → AC
| # набл. | Owner decision (Q) | Раздел УХ | AC |
|---|---|---|---|
| 1 (нет оси/узла) | — (баг, не вопрос) | §8.1 | AC1 |
| 2 (зубцы) | Q1 | §8.2 | AC2 |
| 3 (ложный разрыв) | Q2 | §8.6 | AC6, AC7 |
| 4 (удаление комнаты) | Q3 | §8.7 | AC9–AC12 |
| 5 (комната из контура) | Q4 | §8.5 | AC5, AC8 |
| 6 (Shift/подпись) | Q5 | §8.3, §8.4 | AC3, AC4 |
Чего не проверял
- Реализацию — на этапе spec её нет; продуктовый код не менялся (подтверждено
git show --stat dca4ed2: только два файла вdocs/specs/). - Тяжёлые гейты (
golden,performance, полный backend-harness,demo/smoke_*) — не запускал: на spec-этапе кода для прогона нет, они относятся кS6/пре-релизу. Легковесные тексто/структурные проверки (git diff --check, сверка ссылок и AC) выполнены вручную вместоnpm run typecheck/test/build— они бессмысленны для этой задачи (изменения только вdocs/, ни один.ts/тестовый файл не тронут). - Точные будущие имена helper/test/smoke файлов и i18n-ключей — согласно §20 п.9 ТЗ и PROCESS.md §7.1, это техническая свобода автора, не предмет ревью ТЗ.
Итог
ТЗ полное, однозначное, каждый AC пронумерован и имеет способ доказательства, продуктовая неопределённость закрыта владельцем до написания документа, технические предположения промаркированы и не подменяют продуктовые решения. Готово к переходу в «Готово к разработке».