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

18 KiB
Raw Blame History

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-кодов, точные имена команды и числа) с текущим деревом. Новых находок делта не создала. Вердикт зелёный, ТЗ готово к разработке.