diff --git a/docs/reviews/SPEC-REVIEW-306-r2.md b/docs/reviews/SPEC-REVIEW-306-r2.md new file mode 100644 index 00000000..e58d4f84 --- /dev/null +++ b/docs/reviews/SPEC-REVIEW-306-r2.md @@ -0,0 +1,162 @@ +# SPEC-REVIEW-306-r4 + +- **Issue:** [#306](https://github.com/Matysh/houseplan-card/issues/306) — Редактор плана: заменить виртуальные стены обычными стенами толщиной 0 +- **Этап:** ревью ТЗ (PROCESS.md §2.4, повторный раунд — §2.10) +- **Заход:** r4 · блокирующих циклов израсходовано (до этого вердикта) 2 из 4 +- **ТЗ:** `docs/specs/306-zero-thickness-walls.md`, HEAD ветки `issue/306-zero-thickness-walls` = `3d7395abc354b072d4ed8ae48809972509dde41` («docs: align zero-wall spec limits») +- **Метка issue:** `S4-spec-review` (полный трек, не `small`/`trivial`) + +## Расхождение метаданных запуска с фактическим состоянием issue (процессная находка, не по ТЗ) + +Входные метаданные этого запуска указывали «Заход: r2 · блокирующих циклов +израсходовано 1 из 4». Это не совпадает с состоянием GitHub — тот же класс +расхождения, который уже фиксировали `SPEC-REVIEW-306-r2.md` и +`SPEC-REVIEW-306-r3.md` для своих запусков: + +- r1 (`904c47e4`) — жёлтый, High 0, Medium 3 (2026-08-25T16:49:42Z) — 1 цикл; +- r2 (`2c801bf5`) — зелёный, High 0, Medium 0 (2026-08-25T16:57:24Z) — цикл не тратит; +- r3 (SHA на момент ревью не разрешается локально: документ r3 называет + `abbd4904`, этот коммит недостижим в текущей истории — по датам и + содержимому (то же сообщение «docs: adapt zero-wall spec to model v8», + 2026-08-26T07:21:56+03:00) это переписанный при rebase-на-`dev` эквивалент + коммита `9283d2ee`; между r2 и r3 в лог влиты посторонние коммиты `dev`, + например `93054823`, что и есть след rebase) — жёлтый, High 0, Medium 1 + (M1: устаревший лимит `500` вместо `MAX_WALL_SEGMENTS=200000`), + 2026-08-26T07:31:54Z — 2-й цикл; +- автор исправил M1 в `3d7395ab` («docs: align zero-wall spec limits», + 2026-08-26T07:33:20+03:00) и передал «на финальный spec-review r4/4» + (2026-08-26T07:33:36Z). + +Провожу разбор как **r4** по фактическому состоянию GitHub, а не как r2. +Это находка процесса запуска ревью, а не находка по содержанию ТЗ #306 — +отдельный issue не заводится (параметр одного прогона, не продуктовый +дефект, прецедент — сам этот issue в r2/r3). + +## Скоуп этого раунда + +Дельта между содержимым, разобранным в r3 (эквивалент `9283d2ee`), и текущим +HEAD (`3d7395ab`): + +``` +git diff 9283d2ee..3d7395ab -- docs/specs/306-zero-thickness-walls.md +``` + +даёт 11 изменённых строк в трёх местах документа (§10 шаг 10, §13, §17 AC13) — +ровно та правка, которую предписал вердикт r3 для закрытия M1. Правка не +меняет ни одного контракта поведения, не задевает новую подсистему и не +сопоставима по объёму с исходной задачей — это учебный пример локальной +дельты по критерию §2.10. Разбор по дельте: заново проверено только M1 и +AC13/§10/§13, чьё доказательство эта правка задевает; остальное — раздел +«Унаследовано». + +## Как проверялось + +- `git diff 9283d2ee..3d7395ab -- docs/specs/306-zero-thickness-walls.md` — + единственный источник дельты, прочитан целиком построчно; +- `grep -n '\b500\b' docs/specs/306-zero-thickness-walls.md` — пусто: + устаревшая цифра из трёх мест M1 (§10 п.10, §13, §17 AC13) удалена + полностью, замена на `` `MAX_WALL_SEGMENTS` (сейчас 200 000) `` / + «любого другого актуального backend-лимита»; +- `custom_components/houseplan/validation.py:1047-1048` — + `MAX_WALLS = MAX_WALL_SEGMENTS = 200_000` подтверждено текущим кодом + (та же строка, что и в r3, повторно проверена — правка ссылается на + реальную константу, не на новую догадку); `:1056` `MAX_OPEN_SPANS = 500` — + как и в r3, это предел удаляемого поля, не итогового каталога, ТЗ его не + использует; +- §20 «Риски и защита» (строка «Atomization превысит лимит» → «atomic + failure, no truncation») уже была сформулирована без конкретной цифры — + делта её не касалась, четвёртое место M1 не требовало правки; +- `node --test test/docs-accept.test.mjs test/process-gate.test.mjs` — + 41 passed, 0 failed, 0 skipped (Linux; автор указывал 40 passed + 1 + ожидаемый Windows-skip — расхождение по площадке, не по существу); +- секции 1 «Сценарий» и 2 «Что человек увидит до и после» (закрытие M1 r1) + и ссылка на `docs/SCOPE.md` J4/J6 перечитаны на текущем HEAD (строки 9-26) — + дельта их не касалась, текст не откатился; +- `docs/SCOPE.md` — `J4`/`J6` существуют в документе (`grep -n "J4\|J6"`), + утверждение §1 не голословно. + +## Закрытие раунда r3 + +| Находка r3 | Чем закрыта | Где видно | +|---|---|---| +| **M1** (Medium, в скоупе) — лимит `wall_segments[]` в ТЗ назван устаревшим числом `500` в трёх местах (§10 п.10, §13, §17 AC13), противоречит уже слитому #282 (`MAX_WALL_SEGMENTS=200_000`) | Все три места переписаны на именованную константу/обобщённую формулировку без хардкода цифры | `docs/specs/306-zero-thickness-walls.md:351-353` («При превышении `MAX_WALL_SEGMENTS` (сейчас 200 000) или любого другого актуального backend-лимита отказать целиком»), `:423-424` («Лимит authoritative-каталога остаётся равен backend-константе `MAX_WALL_SEGMENTS` (сейчас 200 000)»), `:605-606` AC13 («Превышение любого актуального backend-лимита… отклоняет весь candidate без truncation/partial apply») — коммит `3d7395ab` | +| Low, снято с записью r1/r3 (нет единого консолидированного блока предположений) | Не переоткрывается — r1 и r3 уже признали формат достаточным при отсутствии открытых продуктовых вопросов | без изменений в этом раунде | + +Других находок r3 не было (High 0, Medium 1 — только M1). + +## Унаследовано из r1/r2/r3 + +Без повторной проверки по существу в этом раунде — дельта `9283d2ee..3d7395ab` +их не касается ни текстуально, ни по содержанию: + +- продуктовые решения владельца по световому режиму (таблица dashed/solid, + запрет фиктивной толщины, единый resolver для Glow и солнца, инвалидация + кэшей при переключении, RU/EN copy под селектором) — проверены в + `SPEC-REVIEW-306-r1.md`/`r2.md`/`r3.md` на SHA `904c47e4`/`2c801bf5`/ + эквиваленте `9283d2ee`; §4 п.4-7, §9.1, §15 текущего файла не менялись; +- соответствие `docs/SCOPE.md` (J4/J6) и отсутствие конфликта с out-of-scope — + §1, §21 не в дельте; +- присутствие `docs/USER-GUIDE.ru.md` в §16/§19 (закрытие M2 r1) — строки + 484, 683 текущей ревизии, не в дельте; +- статусы compatibility-реестра `deprecated-read`/`migrate-on-write` + (закрытие M3 r1) — §6.2, строки ~172-175, проверены в r3 прямым + обращением к `scripts/config-field-registry.mjs`/`docs/CONFIG-COMPATIBILITY.md`, + не в дельте r3→r4; +- целевая модель v8→v9 на authoritative `wall_segments[]`, stable ID/lineage + #282, backend-диапазоны `cm` для `wall_segments`/`room_drafts`/`partitions`/ + `wall_columns` — проверены в r3 по коду (`validation.py`), эта дельта их не + меняет; +- AC1, AC2, AC3, AC4, AC5, AC6, AC7, AC8, AC9, AC10, AC11, AC12, AC14, AC15, + AC16, AC18 — не в дельте, наследуются из r3 без повторного разбора; +- i18n-таблица §15, touch/accessibility §14 — не в дельте; +- release-артефакты §19 (оба changelog, оба user-guide, канонические + документы подсистем) — не в дельте. + +**AC13** и связанный текст §10 п.10, §13 — единственные места, разобранные +заново в этом раунде (см. «Как проверялось» и таблицу закрытия выше); AC17 +(перф-бюджеты) перечитан целиком заново, так как его формулировка находится +в §13, но сам перф-контракт (fingerprint, отсутствие rebuild на HA tick, +benchmark-пороги) не изменился словом — дельта тронула только соседнюю +строку про лимит записей. + +## Находки + +Нет. High: 0, Medium: 0. + +## Что проверено и корректно + +- M1 закрыт по существу, не декларативно: три из трёх мест исправлены + идентичной по смыслу формулировкой, привязанной к реальной именованной + константе, а не к новому хардкоду; четвёртое упомянутое в r3 место (§20) + не требовало правки, так как не содержало числа; +- исправление не создало нового технического долга: вместо конкретной + цифры документ теперь ссылается на «текущий backend-лимит» — формулировка + переживёт будущее изменение константы без повторного устаревания; +- docs/process gate зелёный (`node --test test/docs-accept.test.mjs + test/process-gate.test.mjs` — 41/41); +- секции 1-2 (§7.1), ссылка на `docs/SCOPE.md`, i18n, touch, release-артефакты + не откатились и не пострадали от точечной правки — дельта минимальна и не + затронула соседний текст. + +## Чего не проверял + +- Не перепроверял AC1-AC12, AC14-AC18 по существу заново — они не в дельте + r3→r4 и не зависят от лимита `wall_segments[]`; их закрытие наследуется из + r3 (см. раздел «Унаследовано»); +- не прогонялись `npm run typecheck`/`npm test`/`npm run build`, browser-смоки, + golden, `python -m pytest tests_backend` — на этапе ревью ТЗ src не менялся + ни в этой дельте, ни в дельте r3→r4; это гейты код-ревью (PROCESS.md §2.7, + §8), здесь неприменимы; +- не проверял заново реестр `docs/CONFIG-COMPATIBILITY.md`/ + `scripts/config-field-registry.mjs` — сделано в r3, дельта их не касается; +- не восстанавливал точную историю rebase (`abbd4904` → `9283d2ee`) + коммит-за-коммитом — установил только, что это тот же контент по времени, + сообщению коммита и последующему diff; для целей этого ревью достаточно, + что дельта М1 считается от контента, который r3 реально видел. + +## Вердикт + +M1 закрыт по существу на всех трёх упомянутых местах, новых находок дельта +не создала. High: 0, Medium: 0 — **зелёный**. + +**Вердикт: зелёный · заход r4 · блокирующих циклов 2/4 · High: 0 · Medium: 0 → в задаче**