docs: review document for #306

Issue: #306
User-Visible: no
This commit is contained in:
claude[bot]
2026-08-26 12:55:27 +03:00
committed by Matysh
parent 799289e73b
commit 916a42e33a
+250 -126
View File
@@ -1,152 +1,276 @@
# SPEC-REVIEW-306-r2
# SPEC-REVIEW-306-r3
- **Issue:** [#306](https://github.com/Matysh/houseplan-card/issues/306) — Редактор плана: заменить виртуальные стены обычными стенами толщиной 0
- **Этап:** ревью ТЗ (PROCESS.md §2.4, повторный раунд — §2.10)
- **Заход:** r2 · блокирующих циклов израсходовано 1 из 4
- **ТЗ:** `docs/specs/306-zero-thickness-walls.md`, HEAD ветки `2c801bf539ed81bf7b4239c0b71ba12c514efc59` («docs: address zero-wall spec review»)
- **Метка issue:** `S4-spec-review` (полный трек)
- **Заход:** r3 · блокирующих циклов израсходовано (до этого вердикта) 1 из 4
- **ТЗ:** `docs/specs/306-zero-thickness-walls.md`, HEAD ветки `issue/306-zero-thickness-walls` = `abbd4904641b196ab9c2ed841600e2b260c75653` («docs: adapt zero-wall spec to model v8»)
- **Метка issue:** `S4-spec-review` (полный трек, не `small`/`trivial`)
## Расхождение метаданных задачи с фактическим состоянием (зафиксировано, не блокирует)
## Расхождение метаданных запуска с фактическим состоянием issue (процессная находка, не по ТЗ)
Метаданные этого запуска ревью утверждали «Заход: r1 · блокирующих циклов
израсходовано 0 из 4». Это не соответствует GitHub: `docs/reviews/SPEC-REVIEW-306-r1.md`
уже существует (коммит `ec76d3b1`), вердикт по нему опубликован комментарием
issue #306 (жёлтый · заход r1 · циклов 1/4 · High 0 · Medium 3), автор внёс
правки коммитом `2c801bf5` и сам передал задачу «на delta-review r2/4»
(комментарий issue от 16:52:05Z). Метка на issue остаётся `S4-spec-review`,
GitHub — приоритетный источник правды (PROCESS.md, преамбула). Провожу этот
разбор как **r2** по §2.10, с бюджетом 1/4 (жёлтый r1 цикл потратил), а не как
первый заход. Это находка процесса инфраструктуры запуска ревью, а не находка
по ТЗ #306 — упомянута для трассируемости, отдельный issue не заводится (не
продуктовый дефект, а несовпадение параметра одного прогона).
Входные метаданные этого запуска указывали «Заход: r1 · блокирующих циклов
израсходовано 0 из 4». Фактическое состояние по GitHub и репозиторию другое —
и это тот же класс расхождения, который уже фиксировал `SPEC-REVIEW-306-r2.md`
для своего запуска:
## Закрытие раунда r1
- `docs/reviews/SPEC-REVIEW-306-r1.md` (SHA `904c47e4`) — вердикт жёлтый,
High 0, Medium 3, опубликован комментарием issue (2026-08-25T16:49:42Z);
- `docs/reviews/SPEC-REVIEW-306-r2.md` (SHA `2c801bf5`) — вердикт зелёный,
High 0, Medium 0 (2026-08-25T16:57:24Z), спущен цикл §4 не тратил;
- после зелёного r2 задача ушла в разработку («Взял: Codex», 16:58:32Z), но
после rebase на `dev` реализация нашла продуктовый конфликт с только что
слитым #282 (comment 2026-08-26T00:18:24Z: model v8 уже материализует
каждый contour atom, включая старые тонкие стены, как `wall_segments[].cm=0`,
и единый default стиля по этому единственному `cm:0` бьёт по одной из двух
групп старых планов);
- владелец принял решение не вводить `zero_kind`/compatibility-marker
(2026-08-26T07:15:44Z) — стены неотличимы по происхождению, а не по решению
спецификации;
- автор переписал ТЗ под target model v9 на authoritative `wall_segments[]`
и явно передал «на независимое spec-review r3/4» (2026-08-26T07:22:47Z).
Вердикт r1 (документ `docs/reviews/SPEC-REVIEW-306-r1.md`, SHA `904c47e4`):
жёлтый, High 0, Medium 3, все в скоупе.
| Находка r1 | Чем закрыта | Где это видно |
|---|---|---|
| **M1** — отсутствуют обязательные первые разделы «Сценарий» и «Что человек увидит до и после» (PROCESS.md §7.1) | Добавлены разделы 1 и 2 с персоной (администратор дома), поверхностью (Plan editor, десктоп), моментом (рисование/толщина/настройка пространства) и однофразовым «до/после» без терминов реализации, со ссылкой на J4/J6 `docs/SCOPE.md` | `docs/specs/306-zero-thickness-walls.md:9-25` |
| **M2** — `docs/USER-GUIDE.ru.md` не назван в §14/§17 (старая нумерация) | RU user-guide явно добавлен в список затронутых модулей и в release-артефакты | `docs/specs/306-zero-thickness-walls.md:444-445` (§16) и `:634` (§19) |
| **M3** — §4.2 предлагал несуществующие статусы реестра `project-in-memory`/`migrate-on-structural-write` | Текст заменён на существующие статусы `deprecated-read` (compatibility-read) и `migrate-on-write` (structural-write/Optimize/import); проверено против `docs/CONFIG-COMPATIBILITY.md` («Status meanings», строки 37-46) и `scripts/config-field-registry.mjs` (`CONFIG_FIELD_STATUSES`, строки 278-284; прецедент `open_to` уже зарегистрирован как `deprecated-read`, прецедент `settings.show_all` — как `migrate-on-write` с идентичным паттерном «read until materialisation, затем удаление») | `docs/specs/306-zero-thickness-walls.md:153-156` (§6.2) |
Все три Medium закрыты по содержанию, не декларативно. Побочный эффект
правки — весь документ перенумерован (вставка двух разделов в начало сдвинула
остальные на +2); проверено построчно (`grep '^## '`), что нумерация
последовательна 1…21 без дублей и пропусков, а все внутренние ссылки `§13`,
`§15`, `§17` (было `§11`, `§13`, `§15`) обновлены синхронно и указывают на
верные разделы (Производительность, i18n, Acceptance criteria
соответственно). Это ровно тот случай из §2.10, когда правка по замечанию
может незаметно сломать нечто, признанное верным в r1 — здесь не сломала.
## Унаследовано из r1
Без повторной проверки в этом раунде принято (документ
`docs/reviews/SPEC-REVIEW-306-r1.md`, SHA `904c47e4`, полный разбор был первым
заходом, §2.10 неприменим к нему самому):
- соответствие `docs/SCOPE.md` (J4/J6), отсутствие конфликта с out-of-scope;
- фактические утверждения ТЗ о текущей системе — диапазоны `cm` в
`validation.py` (1..100 для walls/room_drafts/partitions, 1..150 для
wall_columns), `PLAN_MODEL_VERSION=7`, лимиты `MAX_* = 500`, состав
существующих модулей §16 (кроме новой строки про `USER-GUIDE.ru.md`, которая
не техническое утверждение, а release-чеклист, закрыта в этом раунде выше);
- соответствие `docs/LIGHT.md` (opaque/transparent boundary), `docs/TOUCH-SUPPORT.md`
(editors desktop-first, View/kiosk blocking floor), полный учёт обоих
комментариев владельца (таблица светового режима §4 п.4, единый resolver
§5.3/§9.1);
- однозначность и проверяемость AC1–AC18 — содержание AC не менялось в этой
правке (менялись только номера разделов, на которые AC ссылаются, и они
проверены выше как согласованные);
- отсутствие открытых продуктовых вопросов к владельцу.
Дельта этого раунда не задевает доказательства AC1–AC18 по существу (их текст
не тронут), поэтому они не разбирались заново по существу, только сверка
пересчитанных ссылок на разделы, что сделано.
Возврат в работу между r2 и этим запуском не был вердиктом ревью с
блокирующими находками — он вызван конфликтом, обнаруженным в реализации
после слияния #282, поэтому по определению цикла (§4: «отправка на ревью →
вердикт с блокирующими находками → возврат») бюджет циклов между r2 и этим
запуском не тратится. Итого до этого вердикта: 1 цикл израсходован (жёлтый
r1), r2 — зелёный, не тратит. Провожу разбор как **r3** по фактическому
состоянию GitHub, а не как первый заход. Это находка процесса запуска
ревью, а не находка по содержанию ТЗ #306 — отдельный issue не заводится
(параметр одного прогона, не продуктовый дефект).
## Скоуп этого раунда
Предмет — дельта `git diff 904c47e4..HEAD -- docs/specs/306-zero-thickness-walls.md`
(112 строк изменено из 654 исходных: три точечные правки плюс механический
сдвиг нумерации разделов). Дельта локальна: не ребейз (issue-ветка не
отставала от `dev` на этом файле), не смена контракта поведения, не новая
подсистема, объём — 17% документа, не сопоставим с исходной задачей. Полный
повторный разбор не требуется по критериям §2.10.
Дельта между r2 (`2c801bf5`) и текущим HEAD (`abbd4904`) — **не локальна** по
критерию §2.10: `git diff 2c801bf5..abbd4904 -- docs/specs/306-zero-thickness-walls.md`
даёт 136 добавленных / 87 удалённых строк (≈31% документа), и это правка,
которая **задевает новую подсистему** — целевую модель хранения меняет с
плоской `space.walls[]`/`open_spans` (v7) на authoritative
`space.wall_segments[]` со stable ID (v8, реализовано #282), а целевая версия
документа поднята с v8 до v9. Меняется контракт identity, миграции, лимитов и
нормализации — ровно тот случай, где §2.10 прямо предписывает полный разбор,
а не разбор по дельте. Провожу разбор целиком, с явным наследованием тех
частей r1/r2, которые модель v8/v9 не затронула по существу (см. раздел
«Унаследовано» ниже).
## Как проверялось
- `git diff 904c47e4..HEAD -- docs/specs/306-zero-thickness-walls.md` —
построчная сверка правки с текстом трёх находок r1.
- `grep -n '§[0-9]' docs/specs/306-zero-thickness-walls.md` и
`grep -n '^## '` — все перекрёстные ссылки на разделы после перенумерации
указывают на правильные заголовки (§13 Производительность, §15 i18n, §17
Acceptance criteria); последовательность заголовков 1…21 без дублей/пропусков.
- `docs/CONFIG-COMPATIBILITY.md:37-46` и `scripts/config-field-registry.mjs`
(полный файл) — подтверждено, что `deprecated-read`/`migrate-on-write`
существуют в `CONFIG_FIELD_STATUSES` и что использование этой пары для
`open_spans`/`open_to` соответствует реальному прецеденту в реестре
(`spaces[].rooms[].open_to` уже `deprecated-read`; `settings.show_all` —
`migrate-on-write` с аналогичным жизненным циклом read-until-materialise).
- `docs/specs/306-zero-thickness-walls.md:444-445,634` — прямая проверка
присутствия `docs/USER-GUIDE.ru.md` в обоих списках.
- `node --test test/docs-accept.test.mjs test/process-gate.test.mjs` — 38
passed, 0 failed, 0 skipped (на Linux; автор указал 37 passed + 1
Windows-only expected skip — тот же тест, различие чисто по площадке, не
расхождение).
- `gh issue view 306 --repo Matysh/houseplan-card --json ...,comments` —
прочитаны все 5 комментариев целиком, включая хендофф правок r1 (16:52:05Z).
- `git log --oneline`, `git show --stat` на `ec76d3b1` и `2c801bf5` — оба
коммита содержат только заявленные файлы (сам ТЗ; предыдущий раунд — только
документ ревью), трейлеры `Issue: #306` / `User-Visible: no` корректны для
документации.
- Продуктовое рассуждение: перечитаны оба комментария владельца и сверены с
текущим текстом ТЗ построчно (единый resolver, оба световых контура,
атомарность настройки на пространство, отсутствие фиктивной толщины,
parity View/iso/export, i18n-копия, тестовая матрица) — все восемь пунктов
дополнения владельца отражены в разделах §5.3, §7.4, §8.1, §9, §14, §15 и
AC1–AC18.
Технические утверждения ТЗ о текущей системе проверены по коду и документам,
не приняты со слов автора:
- `git show --stat` / `git log --follow` на историю issue #306: коммиты
`dc6d0aaf`, `41469d0a`, `0436850d`, `20070a75`, `abbd4904` и все 11
комментариев issue прочитаны целиком (`gh issue view 306 --json body,comments`);
- `custom_components/houseplan/const.py:54` и `src/plan-optimizer.ts:42` —
`PLAN_MODEL_VERSION = 8` подтверждён как текущий (не 7, как было на момент
r1) — согласуется с заявленным ТЗ переходом «v8 → v9»;
- `src/wall-thickness.ts:215` — `clampWallCm` существует, используется в
местах, которые ТЗ требует сделать zero-aware (АС2/АС11);
- `custom_components/houseplan/validation.py:1394-1405` —
`WALL_SEGMENT_SCHEMA.cm` уже `Range(min=0, max=100)` (backend принимает
`cm:0` для `wall_segments[]` уже сейчас, после #282); `ROOM_DRAFT_SCHEMA`
(:1425) и `PARTITION_SCHEMA` (:1448) — всё ещё `Range(min=1, max=100)`,
`WALL_COLUMN_SCHEMA` (:1471) — `Range(min=1, max=150)`. Формулировка §6.1
ТЗ («Backend принимает cm: 0..100 для wall_segments[], room_drafts[] и
partitions[]») соответствует действительности как целевое состояние: часть
уже верна, часть (`room_drafts`, `partitions`) требует правки — ТЗ не
выдаёт частично готовое за полностью новое;
- `custom_components/houseplan/validation.py:1038-1070` — прямая проверка
лимитов, см. находку M1 ниже;
- `docs/specs/282-stable-wall-segment-identity.md` (§6.5, AC7, разделы про
`walls[]` compatibility projection) — подтверждает заявления ТЗ §5.2 о том,
что `space.walls[]` уже сейчас генерируемая проекция, а не источник истины,
и что `wall_segments[]` уже authoritative для identity;
- `scripts/config-field-registry.mjs:206-219` и
`docs/CONFIG-COMPATIBILITY.md:37-46` — `spaces[].rooms[].open_to` уже
зарегистрирован как `deprecated-read`; статусы `deprecated-read`/
`migrate-on-write`, на которые ссылается §6.2 ТЗ, существуют в реестре;
- `docs/USER-GUIDE.ru.md` — grep `Граница` подтверждает, что инструмент
документирован (строки 432, 483, 537, 1510 и др.) и требует правки, что ТЗ
фиксирует в §16/§19;
- `docs/TOUCH-SUPPORT.md` — формулировки «desktop-first», «best effort»
совпадают с §14 ТЗ;
- `src/open-spans.ts` (781 строк) и `sharedBoundary` (найден в 5 файлах,
включая `src/logic.ts`) существуют — ссылки §5.3/§10 п.2 на существующий
resolver не выдуманы;
- `node --test test/docs-accept.test.mjs test/process-gate.test.mjs` — 40
passed, 0 failed, 0 skipped (Linux; ближе к последней ревизии автора,
который называл 37/39 passed + ожидаемый Windows-skip — разница чисто по
площадке и времени, не расхождение);
- `ls demo/smoke_*.mjs | wc -l` = 192 — для справки; новых смоков в этом ТЗ
не требуется прогонять (спецификация, не код), упомянуто в §17/§18 ТЗ как
будущий gate код-ревью.
## Закрытие раунда r2
r2 (`docs/reviews/SPEC-REVIEW-306-r2.md`, SHA `2c801bf5`) был **зелёным**,
High 0, Medium 0 — открытых находок к закрытию в этом раунде нет. Все три
находки r1 (M1 разделы «Сценарий»/«Что человек увидит», M2 отсутствие
`USER-GUIDE.ru.md`, M3 несуществующие статусы реестра) были закрыты уже в r2
и остаются закрытыми: соответствующий текст (§1-2, §16/§19 упоминания
`USER-GUIDE.ru.md`, §6.2 статусы `deprecated-read`/`migrate-on-write`)
присутствует и в текущей ревизии `abbd4904` — переработка под model v8 не
откатила ни одну из трёх правок (проверено построчно по текущему файлу,
номера строк указаны в разделе «Унаследовано»).
## Унаследовано из r1/r2
Без повторной проверки по существу в этом раунде принято — переработка под
model v8 не касалась этих частей текстуально и по содержанию:
- продуктовые решения владельца по световому режиму (таблица dashed/solid,
запрет фиктивной толщины, единый resolver для Glow и солнца, инвалидация
кэшей при переключении, RU/EN copy под селектором) — документы
`SPEC-REVIEW-306-r1.md`/`r2.md`, полностью проверены на SHA `904c47e4`/`2c801bf5`,
текст §4 п.4-7, §9.1, §15 текущей ревизии не отличается по смыслу;
- соответствие `docs/SCOPE.md` (J4/J6) и отсутствие конфликта с
out-of-scope — раздел 1 ТЗ не менялся по сути между r2 и r3;
- присутствие `docs/USER-GUIDE.ru.md` в §16/§19 (M2 r1) — строки 483-484, 682
текущей ревизии;
- статусы compatibility-реестра `deprecated-read`/`migrate-on-write` (M3 r1) —
§6.2, строки 172-175 текущей ревизии, повторно подтверждены и в этом раунде
прямой проверкой реестра (см. «Как проверялось»), а не только по наследству;
- i18n-таблица §15 (ключи `space.zero_wall_*`, `toast.zero_wall_*`,
`gs.zero_walls_migrated`) — не менялась между r2 и r3, RU/EN парность есть;
- touch/accessibility требования §14 — не менялись по существу.
Дельта r2→r3 не касается доказательств AC1, AC2, AC5, AC6, AC7, AC14, AC16 —
их текст либо не менялся, либо менялся только терминологически (ссылки на
`wall_segments[]` вместо `walls[]`) без изменения проверяемого поведения; они
не переразбирались заново по существу. AC3, AC4, AC8, AC9, AC10, AC11, AC12,
AC13, AC15, AC17 разобраны заново ниже, так как их доказательство прямо
зависит от модели v8/v9, миграции и лимитов.
## Находки
Нет находок уровня High или Medium в этом раунде. Все три Medium из r1
закрыты по существу (см. таблицу выше), новых находок делта не вносит.
### M1 (Medium, в скоупе) — лимит `wall_segments[]` в ТЗ устарел и противоречит уже слитому #282
Low, снятая ревьюером без правки: r1 отметил отсутствие консолидированного
блока «принято предположительно, поменять свободно» — в r2 он также не
появился отдельным блоком, но оставшиеся технические допущения (имя модуля
`src/zero-walls.ts`, разбиение `houseplan-card.ts`) явно помечены в тексте как
свободные для изменения (§5.3, §16). Дальнейшая консолидация не даёт
дополнительной проверяемости — снимаю находку окончательно, как и в r1.
ТЗ трижды называет лимит записей числом **500**:
- §10 шаг 10: «При превышении 500 `wall_segments[]` или любого лимита отказать целиком» (`docs/specs/306-zero-thickness-walls.md:352`);
- §13: «Лимит записей остаётся 500; результат не truncates» (`:423`);
- §17 AC13: «Лимит 500, invalid span, opening conflict или revision conflict отклоняет весь candidate» (`:604`);
- §20, риск «Atomization превысит лимит» → «atomic failure, no truncation» — привязан к той же цифре.
Фактический предел `MAX_WALL_SEGMENTS` в `custom_components/houseplan/validation.py:1048`
равен **200 000**, не 500. Это не опечатка автора, а устаревший факт: до #282
`MAX_WALLS` действительно был `500` (подтверждено `git log -p -S
"MAX_WALL_SEGMENTS"`, коммит `b336eee9`: `-MAX_WALLS = 500` /
`+MAX_WALLS = 200_000` / `+MAX_WALL_SEGMENTS = 200_000`, с комментарием в коде
«v8 atomises room boundaries» — лимит был поднят именно потому, что
атомизация контура увеличивает число записей). Ревью r1 (2026-08-25T16:49,
до слияния #282 в `dev`) корректно зафиксировало «лимиты `MAX_* = 500`» как
факт **на тот момент**. #306 переписан под model v8 (после слияния #282,
комментарий 2026-08-26T00:18) и в остальном тексте последовательно опирается
на `wall_segments[]` как authoritative-каталог (§5.2, §6.1, §16) — но
конкретно эту цифру ревизия «adapt to model v8» не обновила ни в одном из
четырёх мест.
Отдельно — `MAX_OPEN_SPANS = 500` (:1056) действительно равен 500, но это
предел удаляемого этим же ТЗ поля `open_spans`, а не `wall_segments[]`; ни
`docs/specs/282-stable-wall-segment-identity.md`, ни код не подтверждают
цифру 500 для итогового каталога — собственный perf-бенчмарк #282 оперирует
масштабом 10 000 атомов (`docs/specs/282-...md:431`), на два порядка выше.
**Почему это Medium, а не Low:** формулировка не «уточнить», а прямое
техническое утверждение, встроенное в проверяемый AC13 и в шаг миграции §10 —
если реализовать буквально, миграция/Optimize начнёт отказывать легитимным
пространствам, которые #282 уже поддерживает (200 000 записей), то есть ТЗ,
как написано, предписывает регресс уже принятой возможности. Это не открытый
продуктовый вопрос (владельцу нечего решать — предел объективно другой), и не
блокирует понимание архитектуры документа — значит, не High. Правка
механическая: заменить «500» ссылкой на актуальный `MAX_WALL_SEGMENTS`
(200 000) или убрать конкретное число из §10/§13/§20 и оставить «действующий
лимит записей», сохранив только в AC13 существующее поведение «превышение
лимита отклоняет весь candidate целиком».
### Снято с записью (Low, не требует правки)
Как и в r1, в документе нет одного консолидированного блока «принято
предположительно, поменять свободно» (PROCESS.md §7.1) — часть технических
допущений оформлена инлайн с пометками свободы («имя можно уточнить без
изменения контракта», §5.3), часть — как явные решения с обоснованием. Ревью
r1 уже приняло этот формат как достаточный при отсутствии открытых
продуктовых вопросов; в этом раунде замечание не переоткрывается.
## AC, разобранные заново (затронуты моделью v8/v9)
- **AC3** (единая семантика всех `cm:0`) — соответствует принятому владельцем
2026-08-26T07:15:44Z решению не вводить `zero_kind`; текст АС и §5.2/§10
п.5 согласованы, критерий проверяемый (source-contract + смешанная v8
fixture).
- **AC4, AC8, AC9, AC11** — используют authoritative `wall_segments[]` и
lineage #282 корректно (§8.1, §8.3, §10 п.3-4); ссылки на «lineage #282»
соответствуют реально реализованному identity barrier (`docs/specs/282-...md`
§6.5 и далее).
- **AC10** — защита проёмов на миграции распространена на **все** итоговые
`cm:0` (§10 п.6), не только на бывшие legacy spans — корректно закрывает
edge case, который отдельно требовала аналитика (comment 0, «Перевод
физического участка с уже размещённым проёмом»).
- **AC12** — read-only и mutation-gate формулировка не изменилась по смыслу
относительно v7-версии, применима к v8/v9 без правок.
- **AC13** — проверена выше в M1: текст в остальном (atomic transaction, no
partial apply, one-deep Undo) корректен и соответствует §10.1; конкретная
цифра лимита — единственный дефект.
- **AC15** — соответствует текущему backend-состоянию (см. «Как проверялось»):
`wall_segments[]` уже принимает `cm:0`, `room_drafts`/`partitions` требуют
правки диапазона — AC формулирует именно это, без завышения того, что уже
сделано.
- **AC17** — бюджеты §13 корректно исключают лимит 500 из перф-раздела нет,
see M1; сам перф-контракт (fingerprint по `space id + geometry revision +
zero_wall_style`, отсутствие rebuild на HA state tick) сформулирован
однозначно и проверяем benchmark-артефактом.
## Что проверено и корректно
- Все три Medium-находки r1 закрыты содержательно, а не декларативно —
проверено чтением кода/документации-источника (`validation.py`,
`config-field-registry.mjs`, `CONFIG-COMPATIBILITY.md`), а не доверием
тексту ТЗ.
- Перенумерация разделов не создала битых перекрёстных ссылок и не задела
содержание AC1–AC18.
- Документ по-прежнему полностью отвечает DoR §2.5: пронумерованные AC с
доказательством, миграция и compatibility решены (теперь корректно), i18n
RU/EN перечислены, touch/performance названы, откат описан, открытых
продуктовых вопросов нет.
- Соответствие `docs/SCOPE.md` (J4/J6) и обоим комментариям владельца — из r1,
делта его не меняет.
- Оба продуктовых раздела §7.1 (сценарий, что человек увидит) присутствуют
и не описывают реализацию;
- открытых продуктовых вопросов к владельцу нет, оба его решения (комментарии
2026-08-25T15:10:53Z о световом режиме пространства и 2026-08-26T07:15:44Z
о запрете `zero_kind`) полностью отражены в §4 и §5.2;
- модель v8/v9 описана не как догадка, а с явной опорой на уже слитый #282,
и эта опора проверена по факту (не по заявлению автора) в разделе «Как
проверялось»;
- AC1-AC18 пронумерованы, у каждого указан способ доказательства
(unit/backend/smoke/golden/perf), формулировки однозначны;
- release-артефакты (§19) включают оба changelog, оба user-guide, канонические
документы подсистем (WALL-THICKNESS, LIGHT, CONFIG-COMPATIBILITY,
ARCHITECTURE, STATUS) и явно требуют bundle sync — соответствует PROCESS.md
§8 и §11.2 таблице класса D;
i18n-таблица симметрична RU/EN, включает пояснение под селектором отдельным
ключом (не только tooltip), что было прямым требованием владельца;
- откат (§12) отдельно разбирает forward compatibility и invalid-downgrade,
без Labs-флага — обоснование («две одновременно пишущие модели — больший
риск, чем флаг снимает») продуктово осмысленно и не противоречит
`docs/CONFIG-COMPATIBILITY.md`;
- зависимости (§21) корректно называют #282 как реализованную основу и не
претендуют на дублирование её identity-writer; #148/#173 помечены как
требующие superseded-note, а не тихо игнорируются.
## Чего не проверял
- Полный повторный разбор AC1–AC18 по существу (не требуется по §2.10: их
текст дельта не касается, только номера ссылок на другие разделы).
- Код — этап spec-review, кода к задаче ещё нет.
- Тяжёлые гейты (smoke/golden/backend/performance) — неприменимо к этапу ТЗ и
к classу C diff (только документация); прогнаны только дешёвые
документационные тесты (`docs-accept`, `process-gate`), как и в r1.
- `docs/specs/README.md` — колонка ссылки на `306-zero-thickness-walls.md` на
месте, но известная проблема с дублирующей колонкой «Статус ТЗ» (PROCESS.md
§7.3 п.1) не в скоупе этой задачи и не проверялась повторно.
- Не прогонялись `npm run typecheck`/`npm test`/`npm run build` — на этапе
ревью ТЗ src не менялся, эти гейты относятся к код-ревью (PROCESS.md §2.7,
§8) и здесь неприменимы;
- не прогонялись browser-смоки, golden, `python -m pytest tests_backend` —
код отсутствует, нечего исполнять; упомянутые в ТЗ файлы тестов
(`test/zero-wall-migration.test.mjs`, `demo/smoke_zero_walls.mjs` и др.)
ещё не существуют, это ожидаемо для стадии спеки;
- не проверялась математика perf-бюджетов §13 (p95 +10%/+5%) эмпирически —
оценена только как формулируемая и измеримая величина, без числового
прецедента на реальном large-house fixture;
- не проверялись все 21 раздел построчно на перенумерацию (в отличие от r2,
где это было предметом дельты) — в этом раунде перенумерации не было,
структура документа (1…21) стабильна между `2c801bf5` и `abbd4904`, что
подтверждено `grep -n '^## '` без более глубокой сверки каждой
внутренней `§N`-ссылки за пределами тех, что упомянуты выше.
## Вердикт
Зелёный. Три Medium-находки r1 закрыты по существу, ни одна не оставлена как
TODO. Новых High/Medium делта не создала. ТЗ готово к разработке.
Одна находка Medium (M1, в скоупе, устаревший лимит `wall_segments[]`),
High — нет. По PROCESS.md §2.4/§4 это жёлтый вердикт: автор правит текст в
трёх/четырёх местах (§10 п.10, §13, §17 AC13, §20), фикс проходит повторный
раунд ревью по дельте (§2.10, дельта в этом случае локальна — правка одной
цифры и её контекста, не новая подсистема).
**Вердикт: жёлтый · заход r3 · блокирующих циклов 2/4 · High: 0 · Medium: 1 → в задаче**