Files
houseplan-card/docs/reviews/SPEC-REVIEW-228-r1.md
T
2026-08-22 10:55:08 +03:00

13 KiB
Raw Blame History

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) не применяется, разбор полный.

Как проверялось

  1. Прочитаны docs/SCOPE.md, AGENTS.md, PROCESS.md (§1–§4, §7.1, §7.2, §12), тело issue #228 и все 4 комментария (аналитика, продуктовые вопросы с defaults, решения владельца, хендофф «ТЗ готово»).
  2. Прочитаны канонические документы подсистемы: docs/CANVAS.md (разделы «Architectural connection overlay», «Planar wall faces», §9 snap/Shift), docs/WALL-THICKNESS.md (модель partitions/openings, диапазон cm 1–100), docs/TOUCH-SUPPORT.md (контракт деградации), docs/USER-GUIDE.ru.md (терминология «Стены», «независимая стена», «проём»).
  3. Каждое фактическое утверждение раздела 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 не меняется). Все шесть утверждений подтвердились точно, ни одной неверной или додуманной ссылки не найдено.
  4. Проверено существование и содержание связанных issue: #137 (closed, узлы привязки при рисовании), #141 (closed, зубцы стыков перегородок), #173 (closed, единый инструмент стен → предложение комнаты), #232 (open, S1-new, подсветка оси под курсором) — все ссылки в ТЗ корректны и не переписывают чужой контракт сверх заявленных точек расширения.
  5. Проверена терминология: «независимая стена» (USER-GUIDE.ru.md:492), «проём» (:59), «Стены» (:326) — используются в ТЗ так же, как в пользовательском гайде, ничего не изобретено.
  6. Проверено, что hp-dialog с кнопками .btn.danger/.btn.ghost уже существует как паттерн (например, _renderDecorEraseConfirm, houseplan-card.ts:10237–10249) — предложение §8.7 (primary/danger/Cancel) не вводит новый визуальный язык, а расширяет существующий на одну кнопку.
  7. Проверен фикстур-профиль AC15: «60-room/60-partition» дословно совпадает с каноническим npm run benchmark:large-house (docs/TESTING.md:1560, 60 комнат/60 partitions/200 устройств/100 проёмов) — не выдуманное число.
  8. Проверены обязательные разделы ТЗ по 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). Все на месте.
  9. Проверено, что раздел 20 («принятые технические предположения») содержит только технические решения (пороги, приоритет tie-break, переиспользование внутренних API) — ни одно не меняет то, что видит или делает пользователь сверх уже утверждённых владельцем 5 defaults.
  10. 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 полей нет, диапазон cm 1–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 пронумерован и имеет способ доказательства, продуктовая неопределённость закрыта владельцем до написания документа, технические предположения промаркированы и не подменяют продуктовые решения. Готово к переходу в «Готово к разработке».