docs: spec #316 revision 2 — registry/compatibility/goldens sections, reachable AC3 fixture

Issue: #316
User-Visible: no
This commit is contained in:
Codex
2026-08-26 21:54:19 +03:00
parent b6de84e528
commit 6205c8b2d7
+67 -9
View File
@@ -1,6 +1,6 @@
# Issue #316 — миграция v9 сама разрешает конфликт «проём ↔ нулевая стена»
Статус: ревизия 1. Родитель: #306 (стены нулевой толщины), контекст: #319
Статус: ревизия 2 (закрывает M1/M2/Low ревью r1). Родитель: #306 (стены нулевой толщины), контекст: #319
(бэкенд-гард — отдельная задача). Решение владельца (чат, 2026-08-26):
конфликт проёма при миграции разрешается автоматически, рисование нигде не
блокируется; выпуск — v1.68.0-beta.4 вместе с #319.
@@ -59,7 +59,7 @@ t·L + length/2]` пересекает интервал атома на обще
Если кандидатов с `cm > 0` нет вовсе: берётся ближайший по расстоянию сегмент
пространства, удовлетворяющий угловому критерию и вместимости, без ограничения
допуска расстояния. Если и таких нет (в пространстве нет ни одного пригодного
сегмента) — проём сохраняется в данных **без `host`** и становится инертным:
сегмента) — проём сохраняется в данных **без `host`** и становится непривязанным (unhosted):
не создаёт тоннель/вырез/тело, не участвует в физике, рендерится по своим
`x/y` как прежде. `hostRoomOpenings` при initial migration пропускает такой
проём вместо исключения; пост-v9 запись, не меняющая этот проём, обязана его
@@ -81,10 +81,11 @@ t·L + length/2]` пересекает интервал атома на обще
- **AC2 (3.1).** После миграции конфига B дверь остаётся на атоме с исходной
толщиной; атомы span'а по обе стороны проёма — `cm: 0`. Доказательство:
юнит-тест на `commitWallSegmentModel`.
- **AC3 (3.2).** Два коллинеарных совпадающих кандидата (контурный +
независимый, кейс #313) — host выбирается по правилу 3.2 и стабилен при
повторном прогоне (идемпотентность: второй прогон байт-идентичен).
Доказательство: юнит-тест.
- **AC3 (3.2).** Достижимая внутри `resolveRoomOpeningHost` неоднозначность:
центр проёма стоит на стыке двух контурных атомов одной стены на границе
смены толщины (оба атома проходят `eligible` — проём короткий и помещается в
каждом). Host выбирается по правилу 3.2 и стабилен при повторном прогоне
(идемпотентность: второй прогон байт-идентичен). Доказательство: юнит-тест.
- **AC4 (3.3).** Проём вдали от всех стен мигрирует в состояние «без host»,
конфиг проходит `CONFIG_SCHEMA` бэкенда, повторная запись его сохраняет.
Доказательство: юнит-тест фронта + бэкенд-тест схемы.
@@ -94,16 +95,73 @@ t·L + length/2]` пересекает интервал атома на обще
- **AC6.** Прогон миграции идемпотентен: `commit(commit(x)) == commit(x)`
байтово на фикстурах AC1–AC4. Доказательство: юнит-тест.
## 5. Риски
## 5. Затронутые поверхности и артефакты
### 5.1 Файлы
- `src/wall-segment-model.ts` — `buildAtoms` (правило 3.1: легаси-кат не
зануляет атом, несущий проём), `hostRoomOpenings`/`resolveRoomOpeningHost`
(3.2/3.3 при `initialMigration`), пропуск непривязанных проёмов.
- `src/houseplan-card.ts` — без новых веток: barrier остаётся; проверить, что
непривязанный проём не ломает существующие писатели.
- `src/space-render.ts` — подтверждено ревью r1: рендер по `x/y` уже работает
для проёмов без host; правок не ожидается (если потребуются — в скоупе).
- `scripts/config-field-registry.mjs`, запись `spaces[].openings[].host=wall`:
`default` и `migration` больше не могут звучать как «required for contour
openings» / «materialize only when exactly one carrier is proven» —
формулировки обновляются на «materialized by migration §3 of #316; a
contour opening may persist unhosted after degraded migration», в том же
коммите, что и код (правило 11).
- `docs/CONFIG-COMPATIBILITY.md` — новый подраздел о непривязанном контурном
проёме как валидном v9-состоянии после деградированной миграции (§3.3):
не участвует в телах/вырезах, рендерится по `x/y`, переставляется picker'ом;
прежний абзац «missing/invalid host … fail dark» уточняется ссылкой.
- `tests_backend` — кейс схемы: v9-документ с контурным проёмом без host
принимается на чтение и запись (AC4).
- `demo/smoke_*` — новый смок репродукции AC1.
### 5.2 i18n
Без изменений: ключи `toast.zero_wall_migration_blocked` и
`wall_model.reason.opening-host` остаются для пост-v9 fail-closed пути (§2);
новых строк не появляется.
### 5.3 Release-артефакты
- CHANGELOG RU+EN — в реализационном коммите (`User-Visible: yes`).
- Golden: правило 3.1 меняет видимое зонирование `cm:0` (атом под проёмом
остаётся телесным) — добавляется сцена «span поверх стены с дверью» в
golden-матрицу; существующие сцены не должны измениться (в них нет
комбинации span+проём) — verify обязан подтвердить.
- USER-GUIDE — без правок: пользовательского UI-контракта не меняется,
поведение «рисование не блокируется» — восстановление обещанного.
### 5.4 Производительность и touch
Perf: правило 3.1 добавляет к атомизации один проход по проёмам пространства
(O(atoms × openings) на миграцию, единожды на документ) — вне горячего пути
рендера; performance-smoke не затрагивается. Touch-контракта правки не
касаются (миграция — не жест).
## 6. Принято предположительно (поменять свободно)
- Порядок tie-break в 3.2: текущий host → расстояние → больший `cm` →
меньший `id`.
- Семантика деградации 3.3: ближайший пригодный сегмент без лимита допуска, и
лишь затем непривязанное состояние; альтернатива «сразу непривязанный без
поиска» тоже согласуется с решением владельца.
- Имя состояния 3.3 в документации: «непривязанный (unhosted)».
## 7. Риски
- Изменение зонирования cm:0 (3.1) сдвигает границы атомов относительно
beta.3 — на документах, уже мигрировавших на beta.3, правило 3.1 не
сработает (span'ы уже удалены, атомы уже cm:0): такие проёмы попадут в 3.2/3.3.
Принято: beta.3 прожила меньше суток, владелец предупреждён.
- «Инертный» проём (3.3) — новое состояние данных; риск ограничен рендером по
- Непривязанный проём (3.3) — новое состояние данных; риск ограничен рендером по
x/y и пропуском в физике; picker уже умеет переставлять проёмы.
## 6. Откат
## 8. Откат
Реверт ветки; миграция снова кидает `opening-host` (поведение beta.3). Данные,
уже мигрировавшие с авто-разрешением, остаются валидными v9-документами.