diff --git a/docs/reviews/SPEC-REVIEW-251-r1.md b/docs/reviews/SPEC-REVIEW-251-r1.md new file mode 100644 index 00000000..e6b1d094 --- /dev/null +++ b/docs/reviews/SPEC-REVIEW-251-r1.md @@ -0,0 +1,237 @@ +# SPEC-REVIEW-251-r1 + +- Issue: [#251](https://github.com/Matysh/houseplan-card/issues/251) — «доступность контроллера не наследуется от управляемой цели» +- Этап: ТЗ на ревью (PROCESS.md §2.4) +- Заход: r1 · блокирующих циклов израсходовано 0 из 4 (первый раунд, разбор полный) +- Артефакт ТЗ: `docs/specs/251-controller-target-availability.md` (355 строк), запись в `docs/specs/README.md:130` +- Ветка: `issue/251-controller-target-availability` +- Ревьюер получил issue и ТЗ без устных пояснений автора; ниже — независимая проверка по коду `dev`. + +## Скоуп ревью + +Диапазон `origin/dev..HEAD` — один коммит `ba0c787` («docs(spec): separate +controller and target availability»), трейлеры `Issue: #251` / +`User-Visible: no` на месте, класс C (документация), правка сама по себе не +требует `User-Visible: yes`. Изменены только `docs/specs/251-*.md` и +`docs/specs/README.md`. Продуктовый код (`src/**`) не тронут — это ожидаемо +для этапа ТЗ. + +Предмет ревью: полный текст ТЗ против §7.1 PROCESS.md (обязательные разделы), +против диагноза в теле issue и трёх комментариев владельца/аналитика, и против +реального кода `src/device-presentation.ts` / `src/device-toggle.ts` / +`src/houseplan-card.ts` — верификация того, что заявленные в ТЗ факты о +текущем поведении не догадка, а точное описание существующего кода. + +## Как проверялось + +1. Прочитаны `docs/SCOPE.md`, `AGENTS.md`, `PROCESS.md` §2.4/§2.9/§7.1/§7.2, + `docs/USER-GUIDE.ru.md` (разделы «Жесты маркера», «Действия», «Визуальные + состояния устройств», §12), `docs/TOUCH-SUPPORT.md`. +2. Прочитано тело issue #251 и все 6 комментариев (диагноз владельца, + актуализация аналитики, claim-комментарий, вопрос Q1, решение владельца, + хендофф на ревью). +3. Гейты этапа spec: + - `node scripts/check-docs.mjs --external` → `Documentation checks passed + (7 files, 10 external links)` — green; + - `node scripts/process-gate.mjs --range origin/dev..HEAD --issues` → + `гейт пройден, предупреждений 0` — green. + Оба совпадают с тем, что заявил автор в хендоффе. +4. Построчная сверка технических утверждений ТЗ с кодом: + - `resolvePresentationSources()` в `src/device-presentation.ts:233-369` — + подтверждено, что для маркера с `controls` `visualSources`/`samples` + строятся исключительно из `lights` (controls-derived + owned light + sources) и **никогда** не читают `d.entities` устройства-контроллера + (battery/LQI/event туда не попадают в принципе, кроме ветки `alarm` в + `criticalSources`). Это точное описание дефекта, не догадка. + - `resolveDevicePresentation()` (там же, 580-711) — `visual = + combineVisualSamples(sources.samples)`, класс `unavail` берётся из + `visual.availability === 'unavailable'` (строка 564) раньше, чем + `working`/`open` — подтверждает утверждение ТЗ §6.1 о приоритете + `unavail` над `working`. + - `src/device-toggle.ts`: `SkippedToggleTarget{ref, entityId, name, reason}` + (37-58), `toggleOperation()` (763-767) возвращает `null`, когда нет + `command`/`operation` — подтверждает опору AC3/AC4/AC5 на реальную, + уже существующую классификацию, а не на новый API. + - `resolveOwnEntity()`/`reasonForSingle()` (405-497) — для одиночной цели + `noneReason` уже мапит `missing → 'unavailable'`, `skippedTargets` + сохраняет причину и имя — ровно то, что нужно для локализованного + сообщения без нового запроса к HA (заявление аналитика подтверждено). + - `_clickDevice()` в `src/houseplan-card.ts:4930-4979` — строка 4932, + `if (!initial || !toggleOperation(initial)) return; // ... quiet no-op` + — это именно тот тихий `return`, который ТЗ называет дефектом второй + части (п.3 «Актуализации аналитики»). Подтверждено чтением, не + исполнением. + - Токст toasta: `src/houseplan-card.ts:16473,17069` — + `