Files
houseplan-card/docs/reviews/SPEC-REVIEW-485-r4.md
2026-09-09 03:50:50 +03:00

24 KiB
Raw Permalink Blame History

SPEC-REVIEW-485-r4

Issue: #485. Материал: ветка issue/485-radar-presence, SHA 2f2e3fcaca98055b93e647fe8e11df0f1567f643 (baseline r3 материал 21950437b4343deead48c955d06191ea15bb567a, докс-only diff, проверено git diff --stat — только docs/specs/485-radar-presence-stage1.md и docs/specs/485-radar-presence.md; коммит docs/reviews/SPEC-REVIEW-485-r3.md (749970bb) в дельту не входит, по прецеденту r2/r3). Этап: spec (S4-spec-review). Заход: r4. Блокирующих циклов израсходовано 2 из 4 (r1 жёлтый — цикл 1/4; r2 зелёный — цикла не образовал, #227; r3 жёлтый — цикл 2/4). Трек: полный (gh issue view 485 — метки P2, feature, S4-spec-review, small отсутствует). Ревьюер ≠ автор.

Скоуп разбора (по дельте, PROCESS §2.9/§2.10, issue #214)

Единственная блокирующая находка r3 — M-1: новый гейт видимости раздела («структурные метаданные адаптера/реестра») тихо исключал ранее принятый адаптер «любой числовой сенсор» (класс range_v1), не оставляя описанного ручного пути его настроить. Найдено два варианта исправления: (1) явный ручной путь-эскейп для неопознанного устройства, либо (2) явное сужение AC/таблицы профилей с отдельным вопросом владельцу. Между r3 и r4 владелец подтвердил Q5-default (issuecomment-5585013213, 2026-09-08T12:18:52Z): вариант (1) — вторичное действие «Это радар присутствия» в дополнительных действиях редактора устройства.

git diff 21950437..2f2e3fca --stat (исключая коммит документа r3):

docs/specs/485-radar-presence-stage1.md | 101 +++++++++++++++++++++++++-------
docs/specs/485-radar-presence.md        |  19 ++++--

Дельта локальна по объёму и по содержанию: это реализация уже принятого владельцем Q5-решения, которое r3 уже разобрал как «новый поведенческий контракт» и проверил широко (точки входа этапов 2/3, docs/SCOPE.md, прецедент условного раздела пылесоса, docs/UX-MODES.md). r4 не открывает новую подсистему и не меняет контракт повторно — он проверяет, что текст фикса точно реализует уже одобренный Q5, не ослабляет ACL/безопасность и не вносит новой недекларированной догадки. Поэтому разбор в этом раунде ограничен: (а) построчная сверка обеих правок с формулировкой Q5-default и с «как чинится» M-1 из r3, (б) чтение всего файла на предмет рассинхронизации формулировок (старый текст, оставшийся противоречить новому), (в) проверка последствий для ACL/WS-контракта (единственное реально новое техническое расширение — доступ к draft-источникам без общего HA-устройства). Остальное (продуктовая рамка, границы этапов, модель идентичности, AC-таблицы C/S2/S3 и S1 кроме S1-19/20, совместимость, touch-декларации, i18n кроме двух новых ключей, перф-бюджеты) дельтой не задето — см. «Унаследовано из r3».

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

  • gh issue view 485 --json labels,state — OPEN, P2, feature, S4-spec-review, small отсутствует: трек не изменился.
  • gh api repos/Matysh/houseplan-card/issues/485/comments — прочитан весь текущий список комментариев issue от последнего разобранного (после r3) до конца; подтверждено, что после хендоффа автора (IC_kwDOTOcLQM8AAAABTOT_XA, 2026-09-08T12:21:18Z) новых комментариев нет — это материал раунда.
  • Найден и прочитан дословно комментарий владельца Q5-default (gh api .../comments -q 'select(.id==5585013213)') — сверен построчно с текстом Q5 default в 485-radar-presence.md:54 и с разделом «Manual entry (Q5)» в stage1.md:93-118: формулировка «вторичное действие в дополнительных действиях», «основной раздел скрыт до выбора», «отмена ничего не сохраняет», «общий переключатель не меняется», «путь исправления сохранённой настройки остаётся» — совпадают дословно по смыслу, расширений сверх решения владельца не найдено.
  • Построчный git diff 21950437..2f2e3fca по обоим файлам (полный текст правки).
  • grep -n -i "manual" docs/specs/485-radar-presence-stage1.md и по общему контракту — проверено отсутствие рассинхронизации: ни один старый фрагмент («completely unidentifiable hardware… cannot be automatically distinguished», «unresolved metadata is not positive evidence», исполнение AC S1-19) не противоречит новому тексту после правки; все ссылки на «ручной путь» согласованно указывают на один и тот же механизм Q5.
  • Проверено, что docs/specs/485-radar-presence-stage2.md:75 и -stage3.md:86 (точки входа «Device editor → Presence on plan → …», не тронуты дельтой) остаются валидны: обе продолжают описывать вход из уже определённого/настроенного радара — ручное объявление лишь добавляет способ, которым радар становится «настроенным» (marker.radar сохранён), не открывает новый вход в этапы 2–3 в обход существующей модели.
  • Проверено расширение WS/ACL-раздела (stage1.md:495-501, «Draft sources use the same strict schema/size caps…»): новый текст явно требует, чтобы (а) существующий маркер принадлежал запрошенному пространству и был may_write, (б) каждый явно выбранный источник был независимо читаем текущим пользователем, (в) само ручное объявление/фронтенд-eligibility не были авторизацией — сервер валидирует граф источников самостоятельно. Это закрывает очевидный риск новой фичи (клиент заявляет «это радар» и получает доступ к чужим данным): проверка per-source ACL и may_write остаётся обязательной независимо от объявления.
  • Проверено i18n: два новых ключа (additional_actions, declare_radar) добавлены с обеими колонками en/ru в единственной таблице §8 stage1; остальные ключи не тронуты дельтой.
  • Проверено, что «где именно живёт эта кнопка» (свёрнутая группа «Additional actions», отсутствие отдельного персистентного флага классификации) явно помечено как реализационный выбор в блоке допущений в конце stage1.md («For Q5, session- local declaration state and the collapsed additional-actions group are implementation choices…») — не догадка, выданная за факт.
  • Перечитан весь диапазон AC S1-19/S1-20 на предмет доказательства и негативного свидетеля по каждому пункту (git diff выше) — оба присутствуют дословно («remove eligibility guard => …», «Require auto identity => generic-setup witness fails», «persist declaration early => cancel-config comparison fails», «bypass ACL or adapter proof => restricted-source/service canary fails»).
  • Проверено, что решение M-1 из r3 не расширяет и не сужает исключения docs/SCOPE.md (запись/тепловая карта/производные сущности) — дельта не трогает docs/SCOPE.md, вопрос ограничен точкой входа в уже существующий редактор устройства, не новым классом данных/хранения.

Гейты

Диапазон затрагивает только docs/specs/*.md (class C); продуктовый код и тесты не тронуты (git diff --stat 21950437..2f2e3fca -- src custom_components — пусто). Validate зелёный на точном материале раунда (2f2e3fca, https://github.com/Matysh/houseplan-card/actions/runs/34225567412, success, запущен 2026-09-08T12:20:55Z) — дешёвые гейты (typecheck, test, build со сверкой копий бандла) на этом SHA подтверждены и повторно не гонялись.

Прогнано самостоятельно, дёшево, напрямую по этому SHA (диапазон докс-only, эти гейты применимы и не покрыты Validate по существу для этой дельты):

Гейт Команда Результат
Markdown/diff-гигиена git diff --check 21950437..2f2e3fca -- docs/specs/485-radar-presence-stage1.md docs/specs/485-radar-presence.md чисто (exit 0)
Документационные проверки node scripts/check-docs.mjs Documentation checks passed (7 files, 12 external links)

tsc/test/build/invariants/смоки/golden/pytest/перфопрофили — не запускал: diff не касается src/**/custom_components/**/*.py, ни один AC этой стадии не требует их прогона для spec-review, и Validate на этом же SHA уже подтвердил дешёвые гейты репозитория в целом.

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

Находка r3 Чем закрыта Где это видно
M-1 — новый структурный гейт видимости исключал ранее принятый адаптер «любой числовой сенсор» (range_v1) без ручного пути настройки; продуктовая граница решена предположением автора, а не владельцем Владелец подтвердил Q5-default: вторичное действие «Это радар присутствия» в свёрнутой группе «Additional actions» редактора устройства для любого нераспознанного реального устройства/сущности (включая standalone sensor без device_id); действие открывает тот же мастер с ручным выбором из range_v1/cartesian_v1/polar_v1/zones_v1/presence_v1, без авто-подстановки и без доп. диалога подтверждения. Основной раздел остаётся скрытым до явного выбора; Cancel/выход/скрытие страницы/смена привязки ничего не сохраняет и не переносит согласие на другое устройство. Сохраняется только валидированный целиком marker.radar по успешному атомарному Save. Добавлена новая AC S1-20 с доказательством и негативными свидетелями; WS/ACL-раздел явно уточнён: объявление не есть авторизация, per-source ACL и may_write проверяются сервером независимо. Добавлены i18n-ключи additional_actions/declare_radar (en+ru). docs/specs/485-radar-presence.md:54 (Q5 default в таблице), :67-79 (§3 UX-абзац с новым действием); docs/specs/485-radar-presence-stage1.md:48-51 (гейт видимости с явной оговоркой про Q5), :71-79 (новый маркированный пункт «explicit… This is a presence radar action»), :93-118 (раздел «Manual entry (Q5)» целиком), :495-501 (уточнённый WS/ACL-абзац), :524-525 (i18n), :611-612 (AC S1-19 обновлена, AC S1-20 добавлена)

Находка закрыта предметно: правка лежит ровно там, где r3 указала место («ручной путь-эскейп»), реализует ровно тот вариант, который r3 предложила первым («Добавить в §2 явный ручной путь… ведущий в тот же мастер… отдельное от двух автоматических путей»), и количественно совпадает с формулировкой владельца — не шире и не уже.

Унаследовано из r3

Принято без повторной проверки в этом раунде, так как дельта их не задевает; основание — SPEC-REVIEW-485-r3 на SHA 21950437b4343deead48c955d06191ea15bb567a (и через неё — r2 на f4bab4a4, r1 на 6550a69e):

  • Продуктовая рамка, границы этапов 1→2→3 и их отнесение к J1/docs/SCOPE.md.
  • docs/SCOPE.md-исключения для производных HA-сущностей и записи/тепловой карты (закрытые в r1→r2) — эта дельта их не расширяет и не сужает.
  • Touch-декларация мастера калибровки этапа 1 (best effort / intentionally degraded) и этапов 2/3 — не тронута.
  • Единая модель идентичности (source_generation, calibration_revision, server_session_id/seq), лимиты, WS-контракт §7 stage1 (кроме уточнённого ACL-абзаца, разобранного в этом раунде).
  • Полнота AC-таблиц C-1…C-8, S2-1…S2-22, S3-1…S3-18 и S1-1…S1-18 (кроме обновлённой S1-19 и новой S1-20, разобранных в этом раунде).
  • Правило скрытия раздела для обычных устройств (лампы/выключатели/температура/ обычный PIR/виртуальный маркер) и сохранение пути ремонта уже настроенного радара.
  • Точки входа этапов 2 и 3 (stage2.md:75, stage3.md:86) — повторно сверены в этом раунде на предмет совместимости с новым ручным путём (см. «Как проверялось»), новых противоречий не найдено.
  • Матрицы совместимости/жизненного цикла, i18n-таблица §8 stage1 (кроме двух новых ключей), перф-бюджеты §10 stage1.
  • Ответы Q1–Q4 и их количественное соответствие тексту.

Находки

Нет. Единственная блокирующая находка r3 (M-1) закрыта предметно и в точности по предложенному варианту; дельта не вносит новых недекларированных догадок, не ослабляет ACL/безопасность и не противоречит унаследованным AC.

Что проверено и корректно

  • Q5-default количественно и дословно совпадает между комментарием владельца, общим контрактом (§3, таблица Q-defaults) и этапом 1 (§2, раздел «Manual entry (Q5)») — три места не разошлись.
  • Новый ручной путь явно не создаёт авторизации: WS/ACL-абзац требует независимой проверки чтения каждого источника и may_write маркера сервером, объявление «это радар» само по себе прав не даёт — закрывает очевидный риск privilege escalation через самообъявление.
  • Реализационные детали (расположение кнопки, отсутствие отдельного персистентного флага) явно помечены как «assumed, change freely», а не выданы за факт.
  • AC S1-20 имеет колонку доказательства и минимум три названных негативных свидетеля (авто-идентичность обязательна → падает; ранняя персистентность → падает; обход ACL/аппаратного адаптера → падает).
  • i18n добавлен в обеих колонках (en/ru) в единственной таблице, второй копии не создано (правило «один источник» не нарушено — новых пользовательских чисел дельта не вводит вовсе).
  • Точки входа этапов 2 и 3 остаются валидны при новом способе получения «настроенного радара» — они читают уже сохранённый marker.radar, а не способ, которым он появился.
  • docs/SCOPE.md не требует правки для этой дельты — вопрос ограничен точкой входа в существующий редактор устройства.
  • Трейлеры коммита 2f2e3fca: Issue: #485, User-Visible: no — верно для докс-only изменения без видимого пользователю поведения (фича ещё не реализована).

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

  • Не перепроверял полностью AC-таблицы C-1…C-8, S2-1…S2-22, S3-18, модель идентичности, совместимость, перф-бюджеты, touch-декларации, продуктовую рамку — дельта их не задевает; раздел «Унаследовано из r3» перечисляет, что принято без повторной проверки.
  • Не запускал npx tsc --noEmit, npm test, npm run build, npm run invariants, браузерные смоки, golden:verify, python -m pytest tests_backend, перфопрофили — diff докс-only, не касается src/**/custom_components/**/*.py; ни один AC пакета не требует их прогона на стадии spec-review; Validate на этом же SHA (2f2e3fca) подтверждает дешёвые гейты репозитория в целом.
  • Не проверял docs/USER-GUIDE.ru.md/docs/USER-GUIDE.md построчно — фича не выпущена, руководство ещё не содержит раздела о радарах (не с чем сверять).
  • Не оценивал реализуемость новых числовых/технических деталей WS-абзаца — они не являются числовыми константами и не помечены как открытый вопрос; явных внутренних противоречий не найдено при построчной сверке.

Вердикт

Зелёный. High — 0, Medium — 0. Единственная находка r3 (M-1) закрыта предметно и без расширения/сужения скоупа сверх решения владельца. Комплект (общий контракт

  • три этапа) готов к переходу S4 → S5 — с оговоркой владельца, повторённой в хендоффе автора: остановиться в S5-ready, реализацию не начинать.

Этот зелёный вердикт цикла не образует и бюджет §4 не тратит (#227): было израсходовано 2 из 4, после этого раунда — по-прежнему 2 из 4.


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

  • Ветка: issue/485-radar-presence, коммит 2f2e3fcaca98055b93e647fe8e11df0f1567f643.
  • ТЗ docs/specs/485-radar-presence-stage1.md на этом коммите.
  • ТЗ docs/specs/485-radar-presence.md на этом коммите.
  • ТЗ docs/specs/485-radar-presence-stage2.md, docs/specs/485-radar-presence-stage3.md — не изменены с r2 (блобы см. SPEC-REVIEW-485-r2.md/r3.md).
  • Validate: https://github.com/Matysh/houseplan-card/actions/runs/34225567412 (success, headSha 2f2e3fca).

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

  • Ветка: issue/485-radar-presence, коммит 2f2e3fcaca98 — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
  • Дерево материала: a72dbb18c130b5f648a5e07570646e9fc2cdaf45
    git log --all --format='%H %T' | grep a72dbb18c130
    
  • ТЗ docs/specs/485-radar-presence-stage1.md, блоб c47c46bec46eda4be832809273fbe30de48cd9a8
    git log --all --find-object=c47c46bec46eda4be832809273fbe30de48cd9a8 -- docs/specs/485-radar-presence-stage1.md
    
  • ТЗ docs/specs/485-radar-presence-stage2.md, блоб b403e73fc26ba0ffb97be4ffa73be067d179880f
    git log --all --find-object=b403e73fc26ba0ffb97be4ffa73be067d179880f -- docs/specs/485-radar-presence-stage2.md
    
  • ТЗ docs/specs/485-radar-presence-stage3.md, блоб c65e28389d762216c47f00249bdb751f3c9d5082
    git log --all --find-object=c65e28389d762216c47f00249bdb751f3c9d5082 -- docs/specs/485-radar-presence-stage3.md
    
  • ТЗ docs/specs/485-radar-presence.md, блоб 3297ed0140265ad86f2072a40cb9bf8097c0674d
    git log --all --find-object=3297ed0140265ad86f2072a40cb9bf8097c0674d -- docs/specs/485-radar-presence.md