From 6e6747dc09fe9cbae6d244e8f19af61d39bd3448 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Sun, 30 Aug 2026 10:45:00 +0000 Subject: [PATCH] docs: review document for #44 Issue: #44 User-Visible: no --- docs/reviews/SPEC-REVIEW-44-r2.md | 190 ++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 docs/reviews/SPEC-REVIEW-44-r2.md diff --git a/docs/reviews/SPEC-REVIEW-44-r2.md b/docs/reviews/SPEC-REVIEW-44-r2.md new file mode 100644 index 00000000..fe628bc0 --- /dev/null +++ b/docs/reviews/SPEC-REVIEW-44-r2.md @@ -0,0 +1,190 @@ +# SPEC-REVIEW-44-r2 + +- Issue: https://github.com/Matysh/houseplan-card/issues/44 +- Этап: spec (ревью ТЗ, PROCESS.md §2.4) +- Заход: r2 · блокирующих циклов израсходовано 1/4 (потрачен на r1, красный) +- ТЗ: `docs/specs/044-filter-grouping-policy.md`, ревизия 3, зафиксирована + коммитом `ba568763` («docs: #44 spec revision 3 per SPEC-REVIEW-44-r1», + единственный файл, 34 добавлено / 16 удалено — `git show --stat ba568763`) +- Предыдущий раунд: `docs/reviews/SPEC-REVIEW-44-r1.md`, вердикт **красный**, + получен на ревизии 2, коммит `3d4c5090` +- Вердикт: **жёлтый** + +## Скоуп ревью + +Разбор по дельте (PROCESS.md §2.9): дельта локальна — один файл ТЗ, +изменения сосредоточены ровно вокруг двух High из r1 (H1, H2), новых +подсистем не задето, продуктовый код не менялся ни разу с r1 (только +докс-коммиты `df1dbccf`, `ba568763`). Полный повторный разбор всего документа +не требуется; передельчиваю только то, что задевает дельта, и то, что дельта +могла сломать по соседству (см. «Унаследовано» ниже за границей проверки). + +Дельта: `git diff 3d4c5090..ba568763 -- docs/specs/044-filter-grouping-policy.md` +— 34/16 строк, три места: заголовок ревизии, «Что человек увидит»/раздел +«Скоуп → 2» (H1), Контракт п.1a + AC4b + План автотестов + Риски (H2). + +## Закрытие раунда r1 + +| Находка r1 | Чем закрыта в ревизии 3 | Где это видно | +|---|---|---| +| H1 — сценарий/AC4 утверждали, что причина `excluded_integration` сегодня не существует и появляется на «Скрытых»; факт неверен, категория `hidden` структурно недостижима для такого кандидата | Раздел «Что человек увидит» и «Скоуп → 2» переписаны: причина уже существует и рендерится на «Доступны» (#29); скоуп задачи сведён к добавлению плейсхолдера `{integration}` в текст, вкладка/значение reason не меняются, перенос категории явно объявлен нерешаемым здесь вопросом. AC4 переписан под факт | `docs/specs/044-filter-grouping-policy.md:23-27, 70-78, 138-140`; факты перепроверены чтением кода — совпадают (`houseplan-editor-runtime.ts:7637`, `src/i18n/ru.json:484`, `row.integration` уже в структуре строки, `houseplan-editor-runtime.ts:11842`) | +| H2 — `roomClimateMap` хардкодит `EXCLUDED_DOMAINS` в обход настраиваемого резолвера; Контракт №3 («один источник для всех потребителей») был неверен | Добавлен пункт контракта 1a: `roomClimateMap` переводится на тот же резолвер, что и discovery; явный climate-opt-in (`optClimate`) остаётся сильнее — ветка не трогается; добавлен AC4b (юнит) и регресс-риск | `docs/specs/044-filter-grouping-policy.md:99-105, 141-144, 173-175`; проверено чтением: `optClimate` действительно существующая ветка (`devices.ts:1488-1492`), вызовы `roomClimateMap` в трёх местах (`devices.ts:1546`, `houseplan-card.ts:11870`, `space-render.ts:301`) и существующие тесты #317 (`test/devices.test.mjs:1304-1426`) зовут функцию без нового параметра — расширение сигнатуры опциональным параметром не сломает эти вызовы, что подтверждает реалистичность «default-путь байт-в-байт» из AC4b | +| L1 — термин «Доступные» вместо канонического «Доступны» (Low, правится при следующей правке текста, отдельного цикла не требовал) | Не исправлено единообразно | См. ниже, «Находки → L1 (сохраняется)» | + +H1 и H2 закрыты по существу: факты исправлены, новый контракт/AC технически +реализуем (проверено чтением кода, а не на слово автора). Но правка H1 +задела не весь документ — два места вне тронутого диапазона остались +буквально с прежним (уже опровергнутым) утверждением. Это отдельная находка +этого раунда, см. ниже. + +## Находки + +### M1 — Ревизия 3 не убрала два места, где документ прямо утверждает то, что H1 уже опроверг: причина будто появляется на «Скрытых» + +**Файл:** `docs/specs/044-filter-grouping-policy.md`, «Риски» (строка 170) и +«Принятые предположения» (строка 201). + +**Что в документе сейчас:** +- Строка 170 (не менялась при правке H1): «Реason-вкладка «Скрытые» + получает новый класс записей — объём ограничен существующим механизмом + вкладки; смок проверяет отсутствие дублей.» +- Строка 201 (не менялась при правке H1): «Причина показывается на + «Скрытых», НЕ в отдельной новой вкладке.» + +**Почему это противоречие, а не стилистика:** ровно эта пара утверждений — +причина оседает на «Скрытых» — и была фактической ошибкой H1 в r1 +(строка 183 ревизии 2, процитирована в SPEC-REVIEW-44-r1.md как то, что +«маскирует» техническое противоречие). Ревизия 3 переписала «Что человек +увидит», «Скоуп → 2» и AC4 так, что причина теперь однозначно остаётся на +«Доступны» (строки 72-78, 138-140: «вкладка НЕ меняется … перенос категории +… здесь не открывается»). Но правка не дотянулась до «Риски» и «Принятые +предположения» — там буквально сохранился текст, отрицающий собственное +исправление документа. Это не гипотетический риск: раздел «Риски» ссылается +на несуществующий по факту «новый класс записей» на «Скрытых» и требует от +смока проверки «отсутствия дублей» там, где по исправленному контракту +вообще ничего нового не появляется; раздел «Принятые предположения» +формулирует как «предположение» то, что теперь прямо противоречит принятому +(и проверенному чтением) решению. + +**Кому это мешает:** реализатор или автор смока, читающий «Риски»/ +«Предположения» отдельно от «Скоупа» (частый паттерн — эти разделы короче и +их пробегают первыми), получит указание строить или проверять поведение +вкладки «Скрытые», которого сама задача явно не создаёт. Ложное срабатывание +дублей на «Скрытых» либо реализация лишней ветки категоризации — именно тот +класс расхождения, который сделал r1 красным. + +**Почему Medium, не High:** сами AC (AC4, AC4b) и нормативный «Контракт +поведения» однозначны и не зависят от этих двух абзацев — блокирующей +невыполнимости AC нет, в отличие от r1, где AC4 была буквально невыполнима +как написана. Дефект — во внутренней непротиворечивости документа, задача +которого — заново подтверждённые факты (H1). Это находка в скоупе ревизии, +которую делает именно этот раунд (H1-правка), поэтому чинится тем же +циклом, без отдельного issue (PROCESS.md, решение 2026-08-19, #202). + +**Что нужно поправить:** строку 170 переписать/удалить (никакого нового +класса записей на «Скрытых» нет — риск, который стоит сформулировать вместо +неё, если он есть: неверно подставленный `{integration}` при отсутствующем +platform-имени, откат на обобщённый текст); строку 201 удалить из +«Принятых предположений» (это больше не предположение, а опровергнутый факт, +раздел уже содержит корректную версию в теле ТЗ). + +### L1 (сохраняется, Low, не блокирует) — Термин вкладки всё ещё «Доступные» в трёх местах, «Доступны» — в одном + +**Файл:** строки 13, 49, 196 — «Доступные»; строка 73 (новый текст ревизии +3, часть правки H1) и строка 138 (AC4) — «Доступны», канонический термин +`docs/USER-GUIDE.ru.md:785` / `device_inbox.tab_available`. + +Ревизия 3 внесла корректный термин именно там, где переписывала текст под +H1, но не выровняла остальные вхождения — документ сейчас использует оба +варианта параллельно. Как и в r1: не блокирует, правится автором в рабочем +порядке при следующей правке текста; отдельного цикла не требует. + +## Унаследовано из r1 + +Без повторной проверки приняты (проверялись в SPEC-REVIEW-44-r1.md на +коммите `3d4c5090`, продуктовый код с тех пор не менялся — только докс- +коммиты `df1dbccf`, `ba568763`, `git log --oneline 3d4c5090..HEAD -- src` +пуст): + +- SCOPE.md: задача закрывает пункт J6/тезис issue («третий вариант» + запрещён), конфликта со SCOPE нет. +- Трек — полный (не `small`), файл ТЗ обязателен и существует; все + обязательные разделы §7.1 присутствуют. +- Резолвер `group_lights` (`devices.ts:1033/1098`) и `exclude_integrations` + (`houseplan-card.ts:3924-3925`, `space-render.ts:245-246`) описаны точно, + включая replace-семантику и `[]` как валидное «ничего не исключать». +- `EXCLUDED_DOMAINS` (`rules.ts:12`, 13 доменов) совпадает с описанием. +- `scripts/config-field-registry.mjs:42-70` — статусы `decision-required`, + паспорта `allow-extra` обоих ключей, план перевода в `current` технически + корректен и имеет прецедент (6 других полей). +- `expected_rev`/транзакционный паттерн Сохранить, прецедент удаления ключа + при возврате к дефолту (`settings.weather_entity`) — реальны. +- `buildDevices(ctx)` — чистая функция, план AC6 (общий вход превью/боевого + пути без копии логики) реализуем технически. + +Эти пункты дельтой ревизии 3 не задеты (правка ограничена ровно тремя +абзацами, перечисленными в «Скоуп ревью» выше), поэтому переносятся без +повторной сверки кода. + +## Как проверялось + +1. Восстановлен SHA r1 (`3d4c5090`) и вердикт из + `docs/reviews/SPEC-REVIEW-44-r1.md` (документ называет SHA явно — не + находка). +2. `git diff 3d4c5090..ba568763 -- docs/specs/044-filter-grouping-policy.md` + — единственный источник дельты этого раунда. +3. `git log --oneline 3d4c5090..HEAD -- src` — пусто, продуктовый код не + менялся; гейты (`tsc`, `test`, `build`, `check-docs.mjs`) неприменимы, + как и в r1 (чистый докс-коммит, `git show --stat ba568763` подтверждает + единственный изменённый файл). +4. Каждый факт из H1/H2-правок перепроверен чтением текущего кода (не на + слово автора): `houseplan-editor-runtime.ts:7629-7642` (`reasonByBinding`, + `integrationByBinding` уже существуют в одной структуре — плейсхолдер + `{integration}` дёшев в реализации), `:11838-11851` (`row.integration` + уже используется в соседней строке шаблона), `src/i18n/ru.json:484` / + `en.json:484` (текущий обобщённый текст), `devices.ts:1435-1533` + (`roomClimateMap`, ветка `optClimate:1488-1492`, вызовы `EXCLUDED_DOMAINS` + — единственное прямое вхождение в `src/**`, перепроверено + `grep -rn "EXCLUDED_DOMAINS\.has("`), три вызова `roomClimateMap` + (`devices.ts:1546`, `houseplan-card.ts:11870`, `space-render.ts:301`), + тесты `#317` (`test/devices.test.mjs:1304-1426, 2157-2166`) — сигнатура + везде трёхаргументная, совместима с опциональным 4-м параметром. +5. Полнотекстовый grep документа по «Доступны»/«Доступные»/«Скрыты» — + выявил M1 и подтвердил L1. + +## Что проверено и корректно + +- Оба High из r1 закрыты по существу, не косметически: факты исправлены, + новый контракт (1a) и AC4b реализуемы без структурных противоречий с + существующим кодом (подтверждено чтением, включая совместимость с уже + существующими тестами #317). +- AC4 в новой формулировке однозначен и проверяем как написан (вкладка, + текст причины, регресс-ветка на «значение reason не меняется»). +- AC4b однозначен: три случая (интеграция вне действующего набора → климат + участвует; интеграция в действующем наборе → не участвует; + явный climate-opt-in побеждает) — тестируемы юнитом без реализации. +- Ссылки на строки кода в новых абзацах (7637, 1491) точны, перепроверены + заново на текущем дереве, а не унаследованы с доверием. + +## Чего не проверял + +- Полный повторный разбор документа вне дельты — по правилу «дельта + локальна», см. «Унаследовано из r1». +- Гейты `tsc`/`test`/`build`/`check-docs.mjs`/смоки/golden/backend/perf — + неприменимо: с r1 не менялось ничего в `src/**`, `test/**`, `demo/**` + (проверено `git log --oneline 3d4c5090..HEAD -- src test demo` — пусто). +- Не проверялась реализуемость точного способа проброса `{integration}` в + `_t()` (нужен ли новый параметр вызова на строке 11849) — это вопрос + кода на этапе реализации, не ТЗ; сам факт наличия данных (`row.integration`, + `integrationByBinding`) подтверждён, механизм интерполяции `_t(key, params)` + подтверждён существующими вызовами в другом месте того же файла. + +## Итог + +Вердикт: жёлтый. High-находок нет — оба High из r1 закрыты по существу и +подтверждены чтением кода, а не на слово автора. Один Medium в скоупе (M1): +ревизия 3 не убрала два места («Риски», «Принятые предположения»), которые +буквально утверждают опровергнутый H1 факт («причина показывается на +«Скрытых»») — внутреннее противоречие документа ровно на той оси, из-за +которой r1 стал красным. Чинится без нового цикла (правка двух абзацев). +Low (L1, термин вкладки) — сохраняется с r1, не блокирует.