6.6 KiB
Issue #281 — честный Resize после outer-partition reconciliation
- Дата: 2026-08-24
- Тип: regression bug · приоритет P1
- Issue: #281
- Ветка:
issue/281-resize-zero-range - Статус ТЗ: одобрено self-review по решению владельца
Связанные контракты: #276, #277, #278, #280;
docs/RESIZE.md, docs/WALL-THICKNESS.md, docs/TESTING.md.
1. Проблема
Eligibility beta.8 проверяет только исходный d=0, поэтому handle выглядит
активным, хотя обе соседние grid-позиции блокируются endpoint-touching
partitions и clampSafeResize() всегда возвращает ноль.
Resize не должен скрыто двигать или игнорировать independent walls. Перед ним явный Optimize обязан канонизировать только доказанно лишние тела; всё неоднозначное остаётся препятствием.
2. Уточнение принятого default после self-review
В аналитическом комментарии Q1 ошибочно утверждалось, что две outer partitions
целевого 44.json не имеют openings. Фактически каждая содержит hosted window.
Буквальный вариант «только без openings» не исправляет заявленный сценарий.
Минимальная системная поправка в пользу принятого пользовательского результата: exact outer duplicate допускается и с hosted openings, только если все они полностью и без конфликтов материализуются как ordinary outer-room openings по тем же identity/geometry/envelope доказательствам #276/#280. Backend требует solid boundary одного либо двух rooms. Ordinary conflicting opening, неразрешимый host или overlap блокирует весь candidate. Resize по-прежнему не двигает и не игнорирует partition.
3. Optimize-контракт
Один reconciliation pass рассматривает solid atomic interval:
shared: ровно два owner rooms, действующий #276 contract;outer: ровно один owner room;- partition exact endpoint-to-endpoint, known fields only, centred envelope;
- нет overlapping second partition, draft или column;
- итоговая толщина
max(roomCm, partitionCm); - every hosted opening полностью покрывается room interval, materializes без потери полей и не пересекает другие openings;
- после rehost ordinary association имеет ровно тот же набор owner rooms.
Partial/composite/virtual/ambiguous/unknown/conflicting случаи byte-equivalent. Apply/reload/repeated Optimize идемпотентны; Undo возвращает partition и hosts.
4. Resize-контракт
SafeResizeOptions содержит реальный grid step. После построения plan resolver
обязан проверить -step и +step тем же validateSafeResize, который
используют preview/commit.
- хотя бы один valid соседний node → handle enabled;
- оба invalid → handle disabled, pointer не захватывается;
- если соседний candidate блокирует immutable physical obstacle, причина
duplicate-physical-wall; иначе существующий deterministic reason либоinvalid-geometry; - формулировка #277 «enabled + zero-only range» отменяется.
Clamp остаётся contiguous и не перепрыгивает препятствие.
5. Acceptance criteria
- Privacy-min fixture с двумя rooms, целевой shared wall, тремя exact outer partitions и hosted windows воспроизводит старый zero range.
- Optimize удаляет только exact duplicates, materializes windows, сохраняет envelope; backend принимает candidate и повторный Optimize no-op.
- После Optimize целевой handle допускает минимум один шаг в обе стороны; fixed topology, две rooms, thickness/openings и segment count сохраняются.
- До Optimize zero-range handle disabled с
duplicate-physical-wall, не захватывает pointer и не пишет config/history. - Partial/longer/unknown/opening-conflict/second partition/draft/column остаются; их handle не становится ложноположительным.
- Полный
C:\Temp\44.json: Optimize candidate проходит frontend/backend, целевая shared wall имеет ненулевой диапазон; inventory не содержит enabled handle без соседнего valid grid node. - Typecheck, unit, build, Optimize/Resize production smokes зелёные; Linux HA test подтверждает outer rehost Apply/reload/Undo.
6. Совместимость, UX и performance
Schema/model version не меняются. Stored result — существующие room wall и ordinary opening. Disabled handle уже использует доступный focus/tap reason и не требует нового UI/i18n. Дополнительные две validations выполняются один раз в memoized eligibility, не на каждом pointermove; Optimize pass остаётся явным, линейным по atomic intervals и candidates.
7. Self-review ТЗ
- Обнаруженное противоречие с приватным input не замаскировано: hosted windows включены только через доказанный rehost, а не через Resize bypass.
- Одна validation функция определяет eligibility, live clamp и commit.
- Negative matrix сохраняет partitions как hard stops, когда proof неполон.
- Exact lifecycle проверяет обе стороны границы: Optimize canonicalization и честную Resize affordance.
Вердикт: approved с описанным минимальным уточнением Q1. Внешнее spec-review пропущено по прямому решению владельца.