Files
houseplan-card/docs/reviews/SPEC-REVIEW-302-r1.md
T
2026-08-25 17:34:18 +03:00

15 KiB
Raw Blame History

SPEC-REVIEW-302-r1

  • Issue: #302 — «Артефакты на стыках стен: дыры в union-геометрии. Переработка механизма стыков + полноценный сет скриншот-тестов»
  • ТЗ: docs/specs/302-junction-node-material.md
  • Ветка: issue/302-junction-node-material, ревьюемый SHA: 3b19111aa5894f624e608b9f7fef31736a4ecdf5 (родитель 4b8f17ba, ровно вершина dev на момент написания ТЗ)
  • Заход: r1 · блокирующих циклов израсходовано 0/4
  • Класс изменения: A (продукт), трек: обычный (не small) — корректно, задача явно затрагивает perf-бюджет и переработку подсистемы, критерии лёгкого трека не выполняются
  • Вердикт: зелёный

Скоуп ревью

Первый заход, разбор полный (§2.9 не применяется — нет r0). Проверялись: тело issue #302 и единственный комментарий автора, docs/specs/302-junction-node-material.md целиком, docs/SCOPE.md, PROCESS.md §1–§9, docs/WALL-THICKNESS.md целиком, исходник src/wall-thickness.ts (4145 строк) — выборочно, по каждому идентификатору и утверждению ТЗ, требующему проверки на существование/точность.

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

  1. Продуктовая рамка. docs/SCOPE.md — задача улинии с миссией («live spatial overview») через качество геометрии плана; это не новая фича, а устранение искажений в самом визуальном представлении дома — прямое следствие J1. Конфликта со SCOPE нет.
  2. Процесс. Issue помечен S4-spec-review, что и запускает этот этап; размер задачи (обычный) обоснован — трогает src/wall-thickness.ts целиком, влияет на perf-бюджет, не подходит под критерии small (§5 PROCESS.md требует «нет влияния на производительность» — здесь влияние прямо названо в §10 ТЗ).
  3. Фактчекинг утверждений о коде и истории, чтобы отделить подтверждённые факты от гипотез, выданных за решение (обязательный пункт инструкции):
    • MITRE_LIMIT, openEps, buildMultiWallNodeMap, wallIntervals, multiWallNodeAt, outsetContour/insetContour, bevelMultiWallBody/bevelMultiWallPaper, unionJunctionPatches, linearWallJoinPatches, stableJunctionPatch, wallBodiesGeometry, wallBodiesUnionPath — все существуют в src/wall-thickness.ts ровно с тем поведением, которое им приписывает ТЗ (grep + прочтение сигнатур).
    • EPS_NODE = openEps × 4 — совпадает буквально с вызовом в multiWallNodesForGeometry (wall-thickness.ts:2035-2036).
    • wallBodiesUnionPath действительно единственная точка входа для обоих рендереров: src/houseplan-card.ts:11687 (Full/Plan) и src/space-render.ts:432 (Static) — вызывают именно её. Утверждение §2 ТЗ «оба рендерера получают результат из одного и того же кода» не догадка, а факт.
    • Ссылки на прежние ТЗ (#141, #172, #197, #229, #249, #271, #272, #275, #279, #288, #290, #296) сверены с содержанием docs/WALL-THICKNESS.md — каждая деталь («R = 1.25×H», NEAR_AXIS_MAX_DEGREES = 0.25, «near-orthogonal», «short ray handoff», сращивание коллинеарных равных стен из #229) находит буквальное соответствие в каноническом документе подсистемы либо в исходнике (src/near-axis.ts:6-7).
    • Все девять смоков из AC9 (smoke_wall_junctions, smoke_junction_patch_resilience, smoke_split_corner_wall, smoke_zero_divider_taper, smoke_wall_thickness*) и smoke_render_perf (AC8) существуют в demo/.
    • demo/golden/matrix.mjs существует и это действительно data-only каталог golden-фикстур (GOLDEN_MATRIX_VERSION), куда естественно ложится новый сет из §13.
    • Нового «детектора дыр» и isPointInPath-инструментария в репозитории сейчас нет (grep пусто) — заявка «новый чистый модуль» корректна, это не дублирование существующего.
    • SHA 4b8f17b, на котором получены цифры 359/360 дыр, существует в истории и совпадает с прямым родителем ревьюемого коммита — воспроизвести довод «дыры родились в базовой фазе» можно на том же дереве.
  4. Смысловая проверка контракта §8, а не только буквенная. Рассмотрены вырожденные и граничные случаи: узел из 2 лучей (веер строится на обеих угловых секторах — внутренней и внешней стороне, поскольку у двух лучей при круговом обходе ровно два соседства); дегенерат mitre при малом угле (обрезается MITRE_LIMIT, переходит в bevel — предотвращает уход материала в бесконечность); связь с историческим классом дефектов «короткий луч короче радиуса ремонта» (#271/#288) — новая механика по построению не продолжает луч вдоль его оси вовсе («конец полосы» — точка ровно у узла, офсетная по перпендикуляру, а не отложенная на расстояние MITRE_LIMIT вдоль луча), поэтому класс дефектов «репэйр перерос короткий луч» не имеет аналога в новой механике — не пробел ТЗ, а архитектурное упрощение, которое стоит явно назвать в фиксации, но не блокирует ревью.
  5. Проверка DoR-состава (§2.5, §7.1 PROCESS.md): сценарий ✓, «что человек увидит» ✓, проблема/причина ✓ (§3 с исполненным доказательством), скоуп и не-скоуп ✓ (§6–7), контракт поведения ✓ (§8), данные/i18n/a11y/privacy ✓ (§9, всё «не меняется» — обосновано отсутствием миграции конфига), perf ✓ (§10, бюджет назван), риски ✓ (§11, три риска с конкретными мерами), AC ✓ (§12, 9 штук, пронумерованы), план автотестов ✓ (§13–14), откат ✓ (§16), release-артефакты ✓ (§15).

Находки

Ни одной находки уровня High или Medium. Два пункта Low — решение ревьюера: сняты с записью, правки не требуют.

  1. Low — способ доказательства AC не продублирован буквально на каждой строке §12. AC1–AC5, AC8 описывают ожидаемый результат словами («детектор §8.4», «попиксельное совпадение», «смок сверяет пути»), а не явным тегом unit/golden/smoke при каждом пункте, как того просит буква §2.5 PROCESS.md. Решение: снимается без правки — §13 однозначно называет механику («каждая сцена: golden крупным планом + детектор §8.4», «юниты: чистые функции веера... и детектора»), и разработчик/ревьюер кода не может трактовать способ доказательства иначе. Формальный тег ничего не добавил бы к однозначности.
  2. Low — нет отдельного раздела «UX». Шаблон §7.1 называет UX отдельным разделом; в этом ТЗ его содержание разнесено между шапкой («Touch editor: not exposed») и §2 («Что человек увидит до и после»). Решение: снимается — задача не меняет ни одного интерактивного пути (только геометрия отрисовки тел стен), содержательно вопрос закрыт, отдельный заголовок был бы пустой формальностью.

Открытых продуктовых вопросов к владельцу нет и это обоснованно: контракт поведения продиктован самим владельцем в комментарии к issue (кандидат-алгоритм из тела issue почти буквально формализован в §8.2), формальные константы детектора отмечены как техническое предположение в §17 с направлением уточнения («только в сторону строгости»), стадийность демонтажа старых слоёв — там же, помечено как свободное для реализации техническое решение. Это редкий случай, когда молчание не является риском: сам факт задачи и её решение исходят от одного и того же человека.

Что проверено и корректно

  • Соответствие SCOPE.md — задача в рамках мандата, не расширяет функциональность.
  • Соответствие процессу — статус, класс изменения, трек, обязательные разделы, трейлеры/release-артефакты названы верно.
  • Все технические идентификаторы, числа и ссылки на историю, на которые опирается контракт §8, проверены на существование и точность прямым чтением кода и docs/WALL-THICKNESS.md, а не приняты на слово.
  • Контракт §8.2–8.4 логически замкнут: покрывает все перечисленные в §8.3 вырожденные случаи, не оставляет геометрического механизма для дыры между соседними веерами (общая вершина — узел, дуги секторов покрывают полный оборот), и делает объективно проверяемым единственное новое утверждение («нет дыр») через детектор с собственной самопроверкой на дырявой фикстуре (мутант hole-detector-blind).
  • AC9 корректно называет регрессионный периметр — все перечисленные смоки существуют и по названию действительно покрывают стыковую механику.
  • Откат (§16), release-артефакты (§15) и риски golden-переснятия (§11.1) учитывают процессные уроки #230/#235 именно так, как того требует PROCESS.md.

Чего не проверял

  • Я не запускал никакие гейты (tsc, npm test, npm run build, golden:verify, смоки) — на этапе ревью ТЗ кода ещё нет, гейты этапа относятся к код-ревью (§2.7 PROCESS.md), а не к ревью ТЗ (§2.4).
  • Не проверял геометрию mitre/bevel численно (не строил прототип и не считал вручную пересечения офсетных прямых) — на этапе ТЗ это не требуется: контракт верифицируется исполнением на код-ревью через детектор §8.4 и golden, а не через ручной пересчёт геометрии ревьюером ТЗ.
  • Не читал полностью весь src/wall-thickness.ts (4145 строк) построчно — прочитаны и сверены только фрагменты, релевантные утверждениям ТЗ (сигнатуры функций, константы, точки вызова wallBodiesUnionPath).
  • Не проверял содержание единственного комментария к issue построчно на предмет более ранних версий ТЗ — комментарий один, зафиксированное решение соответствует финальному ТЗ.

Итог

docs/specs/302-junction-node-material.md готово к переходу в S5-ready. Продуктовая рамка ясна, контракт поведения проверяем объективным детектором и golden-эталонами, риски демонтажа старого стека названы и покрыты регрессионным периметром (AC9), технические предположения отделены от решения и помечены как свободные к изменению.