Files
houseplan-card/docs/reviews/SPEC-REVIEW-462-r2.md
T
2026-09-05 16:00:54 +03:00

25 KiB
Raw Blame History

SPEC-REVIEW-462-r2

  • Issue: https://github.com/Matysh/houseplan-card/issues/462
  • Спецификация: docs/specs/462-card-resource-registration.md, коммит e9e3d6bd (ветка issue/462-card-resource-registration, HEAD на момент ревью — тот же SHA)
  • Трек: полный
  • Заход: r2 · блокирующих циклов израсходовано 1 из 4 (лимит на полном треке — 4)

Материал раунда r1 (для дельты)

  • Предыдущий вердикт: жёлтый · заход r1 · High: 0 · Medium: 1 → в задаче (комментарий issue, 2026-09-05T11:03:23Z).
  • SHA в самом вердикте (комментарии issue) не назван — это находка процесса фиксации, отдельно от содержательного разбора (см. «Находки», Low-2). SHA восстановлен из документа docs/reviews/SPEC-REVIEW-462-r1.md, где он назван явно: 12ddd107a9cdd9b12ea8411360760f684f5293c1, и подтверждён порядком коммитов (910eedb4 docs: review document for #462 — публикация документа r1 — следует сразу за 12ddd107, до 8973431f, который отвечает на находку r1).
  • Дельта этого раунда: git diff 12ddd107..e9e3d6bd -- docs/specs/462-card-resource-registration.md (151 изменённая строка), двумя коммитами: 8973431f («Замечание SPEC-REVIEW r1 исправлено» + новый YAML resource_mode контракт + источник touch-target) и e9e3d6bd («устранены технические двусмысленности» — retry timing/cancellation, нормализация версии, translations category, card-level overlay в ранних render-states, kiosk-guard дополнения).

Дельта не локальна: она вводит новый терминологический контракт поведения HA («YAML resources mode» vs «Legacy full-YAML dashboard mode», см. ниже) и меняет формулировку четырёх AC (AC1, AC3, AC12, AC13) плюс план тестов и риски. По правилу «смена контракта поведения → полный разбор» я перечитал документ целиком (§1–22) и проверил новые технические утверждения по коду HA, а не только территорию, формально задетую диффом.

Скоуп ревью

Прочитано перед разбором: docs/SCOPE.md (Core user jobs, J4), AGENTS.md, PROCESS.md §1–10, тело issue #462 и все 8 комментариев (включая решение владельца о тихой kiosk-перезагрузке и аналитику 2026-09-05), документ и находки SPEC-REVIEW-462-r1.md, docs/UX-MODES.md (Kiosk mode), docs/TOUCH-SUPPORT.md. Сам документ ТЗ — целиком, §1–22.

Как проверялось

Ревью состязательное: issue + ТЗ + код dev + прямая проверка технических утверждений о платформе HA, без доверия формулировке «по официальному контракту HA» на слово (именно так был подписан коммит 8973431f).

  1. Материал среды. pip index versions homeassistant в этом окружении зеркалирует PyPI и обрывается на 2025.1.4 (последняя доступная версия) — то же ограничение уже зафиксировал r1 («не проверялся HA 2026.8 напрямую»). Скачан homeassistant==2025.1.4 (pip download --no-deps) и прочитан исходник компонента lovelace.
  2. Ключевая новая находка. homeassistant/components/lovelace/__init__.py (2025.1.4) содержит единственный CONFIG_SCHEMA для домена lovelace:
    vol.Optional(CONF_MODE, default=MODE_STORAGE): vol.All(vol.Lower, vol.In([MODE_YAML, MODE_STORAGE])),
    vol.Optional(CONF_DASHBOARDS): ...,
    vol.Optional(CONF_RESOURCES): [RESOURCE_SCHEMA],
    
    Один mode одновременно решает: (а) в YAML ли dashboard, (б) читаются ли resources: из YAML. В ветке else (mode != yaml, т.е. storage — умолчание) код явно делает _LOGGER.warning("Lovelace is running in storage mode. Define resources via user interface"), если yaml_resources is not None — то есть подтверждает, а не опровергает исходную посылку issue («в storage-режиме lovelace.resources из YAML игнорируется целиком»). Отдельного ключа resource_mode, который расцеплял бы «источник ресурсов» и «режим dashboard», в схеме нет. grep -r resource_mode по всему распакованному пакету (.py, все файлы) — ноль совпадений. grep -rn resource_mode по всему репозиторию houseplan-card вне docs/specs/462-*.md — тоже ноль: концепция не встречается больше нигде в кодовой базе, документации или прежних раундах.
  3. Попытка проверить внешний источник. WebSearch/WebFetch недоступны в этой сессии («haven't granted it yet» на оба вызова, дважды). Верификация ограничена локальным кодом платформы и внутренней согласованностью документа — этого достаточно, чтобы поднять находку, но не достаточно, чтобы на 100% исключить более поздний upstream-релиз (ниже, «Чего не проверял»).
  4. Проверка синхронности persistent_notification.async_create. §9 теперь утверждает: флаг «уведомление создано» пишется «сразу после того, как синхронный callback persistent_notification.async_create вернулся без исключения». Подтверждено в исходнике 2025.1.4: homeassistant/components/persistent_notification/__init__.py — функция помечена @callback (не async def, не корутина), тело — синхронная запись в dict + async_dispatcher_send, реальных исключений в штатном пути нет. Формулировка точна.
  5. Проверка card-level overlay в ранних render-состояниях (§11.2). src/houseplan-card.ts:11282-11320 — реальность подтверждена: fixed.kind === 'pending', 'invalid' и !model.length действительно возвращают три независимых <ha-card>...</ha-card> шаблона до основной сцены. Требование «отдельные копии разметки в render-ветках не становятся независимыми состояниями» — не выдумка, а корректный ответ на реальную структуру кода; без него легко забыть плашку в одной из трёх веток.
  6. Проверка закрытия Medium-находки r1 (баннер против тоста #353) — по тексту нового §11.2 и обновлённых AC12/§16 (ниже, «Закрытие раунда r1»).
  7. Проверка закрытия Low-находки r1 (число 44×44 без источника) — §22 п.8.

Находки

High — новый контракт lovelace.resource_mode: yaml не подтверждён и

противоречит и коду HA, и собственной посылке issue

Введено в этом раунде (8973431f, отсутствовало в редакции r1). §5, §12, AC1 и план тестов (§16 «Docs/mutation») теперь утверждают, что в «HA 2026.2+» lovelace.resource_mode: yaml — независимый от lovelace.mode ключ, который подключает YAML-ресурсы к storage-managed dashboard. Формулировка прямая, без оговорки «предположение»: «Нельзя утверждать, что lovelace.resources всегда игнорируется storage-managed dashboard: в HA 2026.2+ именно resource_mode: yaml поддерживает YAML-ресурсы независимо от режима dashboard» (docs/specs/462-card-resource-registration.md:405-408). Коммит 8973431f в issue подписан «по официальному контракту HA» — то есть подан как проверенный факт, не как гипотеза.

Что не сходится:

  • В единственной доступной для проверки версии HA (2025.1.4, актуальная в индексе pip этого окружения) ключа resource_mode не существует нигде — ни в lovelace, ни где-либо ещё в пакете. Единственный mode управляет и dashboard, и тем, читаются ли resources: из YAML.
  • Это прямо противоречит тому, что сама схема делает сегодня: resources: под lovelace: действительно игнорируется (с explicit warning) при mode: storage — то есть исходная посылка issue («в storage-режиме lovelace.resources из YAML игнорируется целиком») подтверждена кодом, а не опровергнута, как теперь пишет ТЗ.
  • Это противоречит собственному телу issue (написано владельцем в тот же день): «в storage-режиме дашбордов (умолчание HA) lovelace.resources из YAML игнорируется целиком» — заявлено как подтверждённый факт полевого разбора, не снято ни одним последующим комментарием.
  • vol.Schema({...}) для домена lovelace в 2025.1.4 не имеет extra=vol.ALLOW_EXTRA (в отличие от внешней обёртки CONFIG_SCHEMA) — значит непредусмотренный ключ верхнего уровня внутри lovelace: обычно валится валидацией конфигурации HA, а не тихо игнорируется. Если resource_mode не появится в реальном будущем релизе именно так, как описано, рекомендованный «современный» sniplet из §12 может не просто не сработать (старая проблема #462), а сломать загрузку lovelace: целиком — то есть задача рискует внедрить дефект хуже исходного, ровно в том месте, которое должно чинить документацию.
  • Утверждение не помечено в §22 («Принятые технические предположения — можно менять на ревью») как гипотеза, хотя структурно — это ровно тот раздел, где ему место, если бы оно было гипотезой, а не фактом.
  • Утверждение приводит к automated docs-contract тесту (AC1, §16) и формулировке AC1 «мутант: … современный mode: yaml вместо resource_mode: yaml … делает docs contract красным» — то есть контракт будет насильно удерживать в README/User Guide формулировку, которую нечем подтвердить, и снимать её будет уже не ревью, а очередной пользовательский репорт, как #462.

Возврат автору. Нужно либо (а) привести проверяемый источник для lovelace.resource_mode (номер release note/PR HA, который это ввёл — тогда формулировка остаётся, но с явной ссылкой), либо (б) убрать разделение на современный/legacy YAML-режим и вернуться к единственному подтверждённому контракту: lovelace.mode: yaml меняет и dashboard, и разрешает resources:, а storage-режим требует UI Resources — то есть к тому описанию, которое уже было верно на r1 и не вызывало вопросов. Пока источник не назван — AC1, §5, §12 и соответствующий пункт §16 остаются недоказанным техническим угадыванием, оформленным как решённый факт. High, блокирует.

Low-1 (наследуется, закрыта) — числовой touch-target 44×44

Была Low в r1 без источника в каноне. §22 п.8 теперь явно помечает число как «локальный accessibility-порог», а не заимствование канона. Формулировка r1 предлагала ровно это — принимаю как закрытую, отдельного действия не требуется.

Low-2 — SHA не назван в вердикт-комментарии r1

Комментарий-вердикт r1 в issue (Вердикт: жёлтый · заход r1 …) не называет SHA материала, на котором получен вердикт — притом что сам документ SPEC-REVIEW-462-r1.md SHA называет дважды (в шапке и в «Материале раунда»). Практических последствий не имело: SHA восстановлен однозначно по порядку коммитов. Не блокирует, но стоит отметить в шаблоне хендофф-комментария на будущее — вердикт-комментарий в issue должен либо называть SHA сам, либо явно отсылать к документу как единственному источнику SHA.

Закрытие раунда r1

Находка r1 Чем закрыта Где видно
Medium: новый version-controller баннер и terminal-тост #353 просят reload независимо и могут показаться одновременно с разными формулировками Явное правило: terminal-тост #353 подавляется только пока видна version-mismatch плашка; network/non-terminal тост и terminal-тост без плашки не подавляются; одновременно два сообщения с одной просьбой не показываются docs/specs/462-card-resource-registration.md:312-318 (§11.2), AC12 (:526-528), план тестов §16 «Browser smoke/golden» (:560-562), риск §19 п.11 (:629-631)
Low: touch-target 44×44 без источника в каноне Помечено как локальное (не канонное) accessibility-решение §22 п.8 (:681-683)

Обе находки r1 закрыты по существу, без новых открытых вопросов по ним самим. Однако правка Medium-находки (коммит 8973431f) в том же дыхании внесла новую, более серьёзную находку — см. «Находки», High — что и есть причина, по которой предупреждение §2.9/#102 в этой задаче не абстрактно: починка одного AC создала риск в другом месте того же коммита.

Унаследовано из r1 (без повторной проверки в этом раунде)

Следующее не тронуто дельтой 12ddd107..e9e3d6bd за пределами описанного выше и принимается по документу docs/reviews/SPEC-REVIEW-462-r1.md (SHA материала 12ddd107a9cdd9b12ea8411360760f684f5293c1):

  • Наличие и содержание обязательных разделов §7.1 PROCESS.md (сценарий, что человек увидит, причина, скоуп/не-скоуп, контракт §8–11, данные/миграция, i18n, AC1…AC13, план тестов, риски, откат, release-артефакты, §22).
  • Существование и смысл символов кода, проверенных в r1: _register_lovelace_resource/_lovelace_resources (custom_components/houseplan/__init__.py:336-378), manifest.json (dependencies без lovelace), system_health_info, CARD_VERSION (src/houseplan-card.ts:402), integration_version в config/get, _preflightVersionsDiffer (houseplan-editor-runtime.ts:9610), _cyclePausedUntil/_zoom/_editing/_pendingPhysicalWrites/ _writesPending/_vacFit.
  • Подтверждённая по реальным wheel homeassistant==2024.6.0 и ==2025.1.4 цепочка зависимостей houseplan → frontend → lovelace (§3) и отсутствие remove_extra_js_url в 2024.6 (обосновывает lovelace_resource_with_ session_fallback, §8.2 абзац после п.9). Эти два факта дельта не затрагивала и я их не переоткрывал.
  • Пригодность homeassistant.helpers.start.async_at_started как CALLBACK_TYPE, совместимого с entry.async_on_unload (§22 п.3, базовая часть механизма; новым в этом раунде является только добавка secondary cancellable delay поверх него — это я перепроверил заново, см. «Как проверялось», п.2 относится к другому вопросу, а сам async_at_started переподтверждать не стал).
  • Полный список из 4 файлов документации с невалидным плоским resources: (README.md:101, README.ru.md:105, docs/USER-GUIDE.md:94, docs/USER-GUIDE.ru.md:93) — дельта не меняла состав списка, только требуемое содержание правки.
  • Обоснование выбора persistent_notification вместо Repairs (§22 п.1) через прецедент custom_components/houseplan/repairs.py.
  • Соответствие SCOPE.md: задача закрывает J4, out-of-scope не задет.
  • AC2, AC5, AC6, AC7, AC8, AC9, AC10, AC11 — формулировки не менялись в дельте (проверено git diff по разделам, см. «Материал раунда r1»); принимаю их однозначность и доказуемость как установленную в r1.

Что проверено и корректно (в этом раунде)

  • Раздел «Закрытие раунда r1» — обе находки закрыты по существу, без формальных отписок.
  • §9 (флаг notification после синхронного async_create) — техническая точность подтверждена по исходнику HA 2025.1.4.
  • §11.2 card-level overlay в ранних fixed-floor/пустых состояниях — требование обосновано реальной структурой render() в src/houseplan-card.ts (три отдельных <ha-card>-ветки), не выдумка.
  • §11.3 новые guard-пункты (нативный HA more-info не участвует по ненадёжному полю; pending layout debounce/грязные позиции устройств блокируют auto-reload) описаны как требования к реализации без ссылки на несуществующие внутренние символы — не нарушают правило «не выдавать догадку за решение», это раздел, где §17 явно оставляет точные имена за реализацией.
  • §22 п.8 (touch-target) и §11.2/AC12/§16/§19 (закрытие toast/banner конфликта) корректно закрывают находки r1 — см. таблицу выше.
  • Нумерация и внутренняя согласованность AC1–AC13 не нарушены дельтой: каждый из четырёх изменённых AC (AC1, AC3, AC12, AC13) по-прежнему однозначен и называет способ доказательства; проблема не в форме, а в фактической достоверности содержания AC1.

Чего не проверял

  • Не проверял HA-версии новее 2025.1.4 напрямую — недоступны в индексе pip этого окружения (то же ограничение, что и в r1). Это ровно тот пробел, из-за которого High-находка выше сформулирована как «не подтверждено», а не как «стопроцентно неверно»: теоретически upstream мог ввести такой ключ именно так, как описано, в версии между 2025.1.4 и «2026.2+», но ни одного подтверждения этому нет ни в коде, ни в вебе (недоступен), ни в остальной части репозитория.
  • WebSearch/WebFetch недоступны в сессии (permission denied на оба вызова) — не смог свериться с release notes/документацией HA напрямую; вся верификация High-находки — по исходному коду ближайшей доступной версии и внутренней логике самого ТЗ.
  • Не прогонял typecheck/test/build — этап spec, кода нет; гейты применимы к код-ревью (§2.7), не к этому этапу.
  • Не проверял AC2, AC5–AC11 заново по существу — формулировки не изменились дельтой, приняты из r1 (см. «Унаследовано из r1»).
  • Не оценивал разделы §13/§14/§17/§18/§20/§21 заново — дельта их не касалась (кроме упомянутых точечных правок в §21 про «три golden» и «десять кадров», которые являются числовым уточнением существующего пункта r1, а не новым контрактом, и не меняют вывод r1 по этим разделам).

Материал раунда

  • Ветка: issue/462-card-resource-registration
  • SHA материала: e9e3d6bd7d8e61a0e7d561da76b19cedb157f32b
  • Дерево: 7bea3d2ffb5216214a550abe845e67d7b4680797
  • ТЗ docs/specs/462-card-resource-registration.md, блоб c507644bf4fb0f5e902ddc4628497e329afeba3c
  • SHA r1 (для дельты): 12ddd107a9cdd9b12ea8411360760f684f5293c1

Материал раунда

  • Ветка: issue/462-card-resource-registration, коммит e9e3d6bd7d8e — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
  • Дерево материала: 7bea3d2ffb5216214a550abe845e67d7b4680797
    git log --all --format='%H %T' | grep 7bea3d2ffb52
    
  • ТЗ docs/specs/462-card-resource-registration.md, блоб c507644bf4fb0f5e902ddc4628497e329afeba3c
    git log --all --find-object=c507644bf4fb0f5e902ddc4628497e329afeba3c -- docs/specs/462-card-resource-registration.md