diff --git a/docs/specs/310-pair-apex.md b/docs/specs/310-pair-apex.md index 671eb556..77e549ce 100644 --- a/docs/specs/310-pair-apex.md +++ b/docs/specs/310-pair-apex.md @@ -1,7 +1,7 @@ # ТЗ #310 — Парный острый стык: полное остриё и срез выступающего торца Issue: https://github.com/Matysh/houseplan-card/issues/310 -Статус: ревизия 1. +Статус: ревизия 2 (после SPEC-REVIEW-310-r1: контракт «без дыр» для узлов-двоек — собственная сеточная проверка, детектор #302 их не видит). База: #309 (визуальный лимит и фаска), #302 (веера, детектор дыр), #271 (адресный латеральный трим). ## 0. Сценарий @@ -44,7 +44,7 @@ Issue: https://github.com/Matysh/houseplan-card/issues/310 ## 5. Риски 1. **Возврат «хвостов»**: полный mitre на почти-параллельных встречных парах формально даёт очень длинное остриё — это осознанное решение владельца (стены, сходящиеся под 5°, сходятся далеко); вырожденные пары (`hit` нет) сохраняют бевел. -2. **Новое вычитание** — дыры на границе среза: гейт — детектор дыр (#302) на фикстуре и сценах; юнит на неизменность тела вне окрестности узла. +2. **Новое вычитание** — дыры на границе среза. Детектор #302 узлы-двойки не видит (`buildMultiWallNodeMap` требует ≥3 лучей): гейт для пар — парный сеточный контракт из AC5; для узлов ≥3 — прежний детектор. Плюс юнит на неизменность тела вне окрестности узла. 3. **Двойной трим** (#271 + #310) в одном узле — интерференция; покрыть юнитом на коротком толстом саппорте пары. ## 6. Release-артефакты @@ -57,13 +57,13 @@ CHANGELOG RU+EN (User-Visible: yes), docs/WALL-THICKNESS.md (§ mitre-joint па 2. **Зубец срезан**: контур узла-двойки — чистый клин; проба в прежней зоне зубца (снаружи грани тонкой, внутри прежнего тела толстой у торца) пуста (юнит по `physicalBodySet.geometry` + пересмотренная сцена `junction-309-spike-dark`). 3. **Адресность**: тело толстой стены на расстоянии > 2·halfDepth от узла байтово прежнее (юнит сравнения колец). 4. **Узлы ≥3 не тронуты**: `junction-309-step/hump-dark` и 16 junction-сцен + owner-repro байтово прежние (golden verify). -5. **Без дыр**: детектор `junctionContractHoles` пуст на фикстуре и сценах (юнит + смок). +5. **Без дыр**: два гейта по типам узлов. Узлы ≥3 лучей — прежний `junctionContractHoles` (фикстура, сцены). Узлы-двойки в него не попадают по построению (`buildMultiWallNodeMap` отбрасывает узлы <3 лучей) — для них вводится **парный сеточный контракт** в юните: в квадратной окрестности узла (радиус 3·max(h), шаг ≤ h/4) точка обязана быть кладкой ⇔ она лежит в (полоса A ∪ полоса B ∪ mitre-патч) − (клинья #310); сверка с фактическим `physicalBodySet.geometry` на узле spike фикстуры `309-junction-teeth` и на синтетических парах (острая, 90°, почти-параллельная). Обоснование корректности вычитания: клин лежит строго снаружи наружной грани соседа, а полоса соседа и патч — не снаружи её, поэтому контракт достижим без дыр. 6. **90° равных толщин**: патч байтово прежний, трим пуст (юнит #309 AC4 остаётся зелёным). 7. **Мутанты**: (a) фаска возвращена в парную ветку — красный; (b) торцевой трим отключён — красный; (c) трим не ограничен окрестностью узла (режет всё тело) — красный. Гварды с типовым прологом tsc+fix-test-build. ## 8. План тестов -Юниты: пара 10+20 (остриё+зубец+адресность), 90°, почти-параллельная пара (бевел-фолбэк), пара с коротким толстым саппортом (#271+#310), детектор на фикстуре. Мутанты §7.7. Golden: пересъёмка spike-сцены, verify остальных. +Юниты: пара 10+20 (остриё+зубец+адресность), 90°, почти-параллельная пара (ограничение reach и бевел-фолбэк), пара с коротким толстым саппортом (#271+#310), парный сеточный контракт (AC5) на spike-узле и синтетике, детектор #302 на фикстуре (узлы ≥3). Мутанты §7.7. Golden: пересъёмка spike-сцены, verify остальных. ## 9. Откат