Files
houseplan-card/docs/reviews/SPEC-REVIEW-33-r2.md
T
2026-08-30 09:33:39 +00:00

185 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SPEC-REVIEW #33 — r2
- Issue: https://github.com/Matysh/houseplan-card/issues/33
- Этап: ревью ТЗ (PROCESS.md §2.4)
- ТЗ: `docs/specs/033-config-schema-lifecycle.md`, ревизия 3
- SHA материала: `1c1f9d8ea4a3e2f32c5cd6150dde5e08bdfc280b`
- Заход: r2 · блокирующих циклов израсходовано 1 из 4 (r1 — жёлтый, потратил
цикл; зелёный вердикт этого раунда цикла не образует, #227)
- Вердикт: **зелёный**
## Скоуп
Ревизия 3 — точечный ответ на три Medium-находки и два Low прошлого раунда
(SPEC-REVIEW-33-r1, SHA `8335191b`), ничего сверх этого. Продуктовая рамка,
класс задачи (A, schema-потребители), трек (полный) и оценка аналитики не
пересматриваются — они не были предметом находок r1 и делта их не задевает.
Дельта — ровно один файл, `docs/specs/033-config-schema-lifecycle.md`,
53 изменённые строки (34 добавлено / 19 удалено), подтверждено
`git diff 8335191b..1c1f9d8e --stat`. Рядом в дереве `src/**` и
`custom_components/**` не менялись с базового SHA r1 (`git diff --stat
8335191b..HEAD -- src/ custom_components/ package.json` пуст) — значит,
ничего из подтверждённого чтением кода в r1 не могло протухнуть за это
время. Делта локальна по критерию §2.10: не ребейз (HEAD ровно на один
docs-коммит впереди материала r1), не смена контракта поведения (контракт
поведения — «ничего в рантайме не меняется» — не тронут), не задета новая
подсистема, объём сопоставим с тремя находками, которые он закрывает.
Полный повторный разбор не требуется; ниже — разбор по дельте плюс
целевая перепроверка того, до чего дельта дотягивается.
## Как проверялось
1. Найден вердикт r1 и SHA материала — оба названы в шапке
`docs/reviews/SPEC-REVIEW-33-r1.md` (`8335191b`), спорить не пришлось.
2. Объявлена дельта: `git diff 8335191b..1c1f9d8e -- docs/specs/033-config-schema-lifecycle.md`
(полный текст сверен построчно).
3. По каждой находке r1 (M1, M2, M3, L1, L2) — отдельная проверка чтением
текущего дерева, что предложенное в ревизии 3 решение не просто иначе
сформулировано, а технически состоятельно (не только «текст ТЗ звучит
иначе», а «то, что он теперь обещает, совместимо с кодом, которого
касается»):
- `scripts/config-field-registry.mjs` — прочитан целиком; подтверждено,
что поля `enforcedBy` и `schema: 'allow-extra'` в текущей форме записей
нет (свободны для добавления), что `CONFIG_FIELD_STATUSES` остался
тем же перечислением из 6 значений (ревизия 3 их не трогает — точно
то, что требовало M1), что записей сейчас 27
(`node --input-type=module` импорт и `.length`), и что ни одна из
четырёх «новых» ID-записей (`decor_default_style`, `furniture`,
`host=partition`) ещё не существует в registry — делта не дублирует;
- `src/logic.ts:898-919` — `SPACE_FILL_MODES`/`ROOM_FILL_MODES`/
`DISPLAY_MODES`/`TAP_ACTIONS` существуют и экспортируются, как и
утверждает исправленный текст (только 3 из 7 пар);
- `src/types.ts:212`, `src/plan-optimizer.ts:285`,
`src/zero-walls.ts`/`houseplan-editor-runtime.ts`/
`houseplan-onboarding-runtime.ts` (литералы `'dashed'`/`'solid'`),
`custom_components/houseplan/validation.py:1254` (`_BG_MODE`) —
подтверждено, что для `opening.type`, `vacuum.trail_mode`,
`zero_wall_style`, `bg_mode` сегодня нет ни одной именованной
экспортируемой frontend-константы (ровно то, что M2 требовал признать
явно) и что предложенные имена `OPENING_TYPES`, `VACUUM_TRAIL_MODES`,
`ZERO_WALL_STYLES`, `BG_MODES` не заняты (`grep` по `src/*.ts` — пусто),
то есть план не столкнётся с коллизией имён при реализации;
- `scripts/config-audit.mjs` (всё, 103 строки) — подтверждено, что
`process.exitCode` сегодня выставляется только на ветках ошибок
разбора (74/79/102), никогда от найденных полей; что код `1` нигде не
занят и не проверяется ни одним потребителем (`grep` по `package.json`
и `.github/workflows/*.yml` на `audit:config`/`config-audit` — только
объявление npm-скрипта, никакого CI-потребления exit-кода), то есть
новый контракт `0/3/2` ревизии 3 не конфликтует с существующим
поведением или скрытым потребителем; заодно перечитан сам факт: `2`
сегодня — единственный ненулевой код, значит выбор `3` для нового
смысла действительно не сталкивается с ним, как и заявляет текст;
- `package.json:19` — `"audit:config": "node scripts/config-audit.mjs"`,
текст ТЗ теперь везде цитирует именно эту команду (L1 закрыт);
- весь файл ТЗ ревизии 3 — построчный поиск «24» не находит ни одного
оставшегося упоминания старого числа, все вхождения — «27» (L2 закрыт
полностью, не только в шапке).
4. Перечитаны критерии приёмки AC1–AC7 целиком — ни один не ссылается на
статус `implemented` или на старый контракт exit-кода: правка текста
Блока 2/3 синхронизирована с разделом AC, который сам по себе делту не
зафиксировал (он и не должен был — AC6 уже был сформулирован достаточно
абстрактно, «различает exit-codes», и лишь уточнён числами 0/3/2).
5. Перечитан документ ревью r1 целиком (не только раздел «Находки») —
сверено, что раздел «Что проверено и корректно» r1 не полагался ни на
один факт, который ревизия 3 меняет (архитектура манифеста, `docs/SCOPE.md`,
§7.1-разделы, «уже реализовано жизнью» для show_all/weather_entity/
aspect/segments — ревизия 3 их не трогает, только меняет способ их
фиксации в registry с несуществующего статуса на поле `enforcedBy`).
6. Дешёвые гейты: `npx tsc --noEmit` на HEAD (`1c1f9d8e`) — чисто, 0 ошибок.
## Закрытие раунда r1
| Находка r1 | Чем закрыта | Где видно |
|---|---|---|
| **M1** — статус `implemented` не существует ни в перечислении, ни в `CONFIG_COMPATIBILITY.md` | Статусная модель не меняется; вместо нового статуса — опциональное поле `enforcedBy` (ссылка на кодовую точку/тест), новые паспорта получают существующий статус `current` | `docs/specs/033-config-schema-lifecycle.md:80-90` (Блок 2, абзац «Актуализация registry как данных»); подтверждено чтением, что `CONFIG_FIELD_STATUSES` (`scripts/config-field-registry.mjs:362-369`) и поле `enforcedBy` совместимы (поля с таким именем в записях сегодня нет) |
| **M2** — 4 из 7 frontend-констант для parity-теста не существуют | Текст явно называет 3 готовые пары отдельно от 4 отсутствующих и описывает их как новую работу этого issue: экспортируемые `as const`-массивы `OPENING_TYPES`/`VACUUM_TRAIL_MODES`/`ZERO_WALL_STYLES`/`BG_MODES`, из которых выводятся существующие union-типы | `docs/specs/033-config-schema-lifecycle.md:59-68` (Блок 2, первый абзац); подтверждено, что ни одно из четырёх имён не занято в `src/*.ts` |
| **M3** — AC6/Блок 3 описывали несуществующее поведение `config-audit.mjs` как «расширение теста» | Явно зафиксирован новый контракт exit-кодов: `0` clean, `3` migration available, `2` invalid (без изменений), с обоснованием выбора `3`, чтобы не конфликтовать с текущим `2`; AC6 переформулирован под тот же контракт | `docs/specs/033-config-schema-lifecycle.md:101-107` (Блок 3, последний абзац) и `:147-148` (AC6); подтверждено чтением `scripts/config-audit.mjs`, что код `1` сегодня свободен и не потребляется CI |
| **L1** — команда в «Что человек увидит» названа неверно (`config:audit` вместо `audit:config`) | Текст исправлен на точное имя npm-скрипта | `docs/specs/033-config-schema-lifecycle.md:22`; сверено с `package.json:19` |
| **L2** — «registry = 24 записи» разошлось с фактическим размером массива (27) | Все вхождения числа в шапке и в разделе «Проблема» заменены на 27 | `docs/specs/033-config-schema-lifecycle.md:8,27`; сверено подсчётом `CONFIG_FIELD_REGISTRY.length` на HEAD — 27; поиском по файлу подтверждено отсутствие оставшихся «24» |
Все пять находок закрыты правкой текста в пределах ревизии 3, без изменения
архитектуры Блока 1 и без обращения к владельцу — как и предполагал вердикт
r1.
## Унаследовано из r1
Следующее принято без повторной проверки — делта его не задевает, и ничего
в дереве (src/**, custom_components/**) с SHA `8335191b` не изменилось:
- соответствие `docs/SCOPE.md` (задача — защитная инфраструктура под J6, не
претендует на пользовательскую ценность) — `SPEC-REVIEW-33-r1.md`, раздел
«Скоуп», SHA `8335191b`;
- присутствие и полнота всех обязательных разделов §7.1 (сценарий, что
человек увидит, проблема, скоуп/не-скоуп, контракт, UX/i18n, модель
данных, AC, план тестов, риски, откат, release-артефакты, принятые
предположения) — `SPEC-REVIEW-33-r1.md`, раздел «Что проверено и
корректно», SHA `8335191b`; ревизия 3 не удалила и не переименовала ни
один раздел (структура файла сверена при чтении ревизии 3 целиком в этом
раунде, см. «Как проверялось» п.4–5, поэтому это скорее переподтверждено,
чем чисто унаследовано);
- архитектурное решение Блока 1 (манифест схемы генерируется из Voluptuous,
а не пишется руками на 212 путей) — не тронуто делтой, корректность
подтверждена в r1 чтением `scripts/config-field-registry.mjs` и
`custom_components/houseplan/validation.py` на SHA `8335191b`;
- факты «show_all/weather_entity/aspect/segments уже реализованы кодом» —
подтверждены в r1 чтением `houseplan-card.ts:3895`,
`houseplan-editor-runtime.ts:9618`, `validation.py:1590,1670` на SHA
`8335191b`; ревизия 3 меняет только способ их фиксации в данных
(`enforcedBy` вместо статуса), не сам факт;
- необходимость заглушек родительских пакетов для импорта `validation.py`
без `homeassistant` — воспроизведено в r1 (`ModuleNotFoundError`), делта
этого блока не касается;
- формулировка не-скоупа (`group_lights`/`exclude_integrations` → #44) —
не менялась.
## Что проверено и корректно
- Все пять находок r1 закрыты по существу, а не только по формулировке:
каждое новое обещание текста (поле `enforcedBy`, четыре новых экспорта,
контракт exit-кодов 0/3/2, точное имя npm-скрипта, число 27) сверено с
текущим деревом и не встречает коллизии имён, полей или уже занятого
значения.
- AC1–AC7 остаются согласованными с телом ТЗ после правки: ни один AC не
ссылается на отменённый статус `implemented` или на прежний
недоопределённый контракт exit-кода; AC6 обновлён в паре с текстом Блока 3.
- Числа в шапке (`212`, `2`, `27`) внутренне согласованы по всему файлу —
расхождений вида «одно число, два значения» не осталось (единственная
такая находка прошлого раунда, L2, закрыта полностью).
- Делта не расширяет скоуп: три новых абзаца — это уточнение уже
анонсированных в ревизии 2 блоков, а не новая работа сверх исходного ТЗ.
## Чего не проверял
- Не проверял по существу архитектурные решения, не затронутые находками
r1 (Блок 1 целиком, фикстуры Блока 3 кроме контракта exit-кода, раздел
«Риски») — они не входят в дельту и не изменились со SHA `8335191b`;
доверие — по разделу «Унаследовано из r1» выше, не молчаливое.
- Не гонял `npm test`, `npm run build`, `node scripts/check-docs.mjs` —
diff раунда docs-only (подтверждено `git diff --stat`), `src/**` не
тронут, эти гейты не сказали бы ничего нового о ревизии ТЗ (то же
основание, что в r1).
- Не гонял смоки, golden, инварианты модели, performance — этап ТЗ, кода
ещё нет, ни один из этих гейтов не применим.
- Не проверял заново оценки сложности/риска и продуктовую ценность из
комментариев аналитики — не предмет ревью ТЗ, не изменились в этом
раунде.
## Гейты — сводка
| Гейт | Прогнан | Результат |
|---|---|---|
| `npx tsc --noEmit` | да, на SHA `1c1f9d8e` | чисто, 0 ошибок |
| `npm test` | нет | diff docs-only, src/** не тронут |
| `npm run build` | нет | то же |
| `node scripts/check-docs.mjs` | нет | diff не касается `src/**` |
| смоки / golden / инварианты / perf | нет | этап ТЗ, продукт не меняется |
## Итог
0 High, 0 Medium, 0 Low. Все пять находок r1 закрыты состоятельно —
проверено не только чтение нового текста, но и совместимость каждого
нового обещания (поле `enforcedBy`, четыре новых frontend-константы,
контракт exit-кодов, точные имена команды и числа) с текущим деревом.
Новых находок делта не создала. Вердикт зелёный, ТЗ готово к разработке.