From 4b81dc2ad9187e1d12eacf2fe8b13826900599e5 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Fri, 28 Aug 2026 12:51:37 +0000 Subject: [PATCH] docs: review document for #318 Issue: #318 User-Visible: no --- docs/reviews/SPEC-REVIEW-318-r1.md | 188 +++++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 docs/reviews/SPEC-REVIEW-318-r1.md diff --git a/docs/reviews/SPEC-REVIEW-318-r1.md b/docs/reviews/SPEC-REVIEW-318-r1.md new file mode 100644 index 00000000..068238ea --- /dev/null +++ b/docs/reviews/SPEC-REVIEW-318-r1.md @@ -0,0 +1,188 @@ +# SPEC-REVIEW — issue #318 · заход r1 + +- Этап: spec (PROCESS.md §2.4) +- Артефакт ТЗ: `docs/specs/318-empty-controller-roster.md` (полный трек; + `docs/specs/README.md` — строка добавлена) +- SHA ревью: `1242a3b1badf13a8785c7e176da2c3f765ccdad8` + (ветка `issue/318-switch-render-state`, коммит "docs: specify empty-roster + controller state", `Issue: #318` · `User-Visible: no` — трейлеры корректны: + коммит документальный, пользовательского поведения ещё не меняет) +- Заход: r1 · блокирующих циклов израсходовано 0 из 4 + +## Скоуп + +Issue #318: маркер физического беспроводного выключателя без единой +собственной сущности registry (`device:` binding активен, `own roster = []`, +`controls: [light.wall_lights]`) навсегда остаётся в приглушённой (`unavailable`) +подаче независимо от состояния управляемой цели. Owner уже принял продуктовое +решение в комментариях issue до написания ТЗ: активный физический +device-binding с пустым собственным roster считается доступным и следует +`controls`; непустой roster без единого живого состояния остаётся +`unavailable` по контракту #251. ТЗ реализует это решение. + +Трек — полный, обоснованно: меняется публичный UX-контракт (строка S05 +таблицы решений `docs/DEVICE-PRESENTATION.md`), затронут общий presentation +resolver на всех поверхностях (plan/preview/hosted Static). Названный критерий +лёгкого трека, который задача не проходит, указан в самом ТЗ. + +Затронутая подсистема: `docs/DEVICE-PRESENTATION.md` / `docs/ARCHITECTURE.md` +(канон availability/status controller), плюс `docs/USER-GUIDE.ru.md` для +пользовательской терминологии. + +## Как проверялось + +1. Прочитан `docs/SCOPE.md` — задача закрывает J1 («что происходит сейчас») + и J3 («быстрое очевидное действие»); ложный сигнал недоступности прямо + противоречит J1. +2. Прочитаны `AGENTS.md`, `PROCESS.md` §1–2.4, §4, §5, §7.1–7.3 — формат + документа, обязательные разделы, бюджет циклов, критерий полного трека. +3. Прочитано тело issue #318 и все 4 комментария: заявка → анализ аналитика с + продуктовым вопросом → решение владельца → хендофф автора ТЗ. Продуктовый + вопрос был ровно один, и он закрыт до старта этого ревью. +4. Прочитан весь файл ТЗ `docs/specs/318-empty-controller-roster.md` (295 + строк) целиком, раздел за разделом на соответствие §7.1. +5. Прочитаны канонические документы: `docs/DEVICE-PRESENTATION.md` (таблица + решений, строки S03–S09), `docs/ARCHITECTURE.md` (цитаты «Yellow means + working» из issue подтверждены как существующий канон), `docs/USER-GUIDE.ru.md` + (раздел 12 «Визуальные состояния устройств», строки 958–1004 — текущая + документированная формулировка, которую ТЗ обязано будет уточнить в коде). +6. Сверены с реальным кодом все технические утверждения диагноза (§3) и + контракта (§6.1–6.3), а не приняты на веру: + - `controllerAvailability()` (`src/device-presentation.ts:208-217`) — + `(d.entities || []).some(...)` на пустом массиве безусловно даёт `false` + → `unavailable`. Диагноз ТЗ («пустой список безусловно даёт unavailable») + подтверждён чтением, не исполнением. + - `resolveHaBindingStatus()` (`src/ha-binding-status.ts:414-463`) — + ветка `kind === 'device'`, `allEntityIds.length === 0`: `isRegistryEntryEnabled(device)` + истинно (устройство активно), `enabledEntityIds = [].filter(...) = []`, + условие `allEntityIds.length && !enabledEntityIds.length` ложно (первый + операнд `0`) → возвращается `{ kind: 'active', enabledEntityIds: [], allEntityIds: [] }`. + Это ровно сценарий #318 и ровно предикат §6.1 ТЗ («active», `bindingKind + === 'device'`, roster `[]`). Подтверждено чтением. + - Термины `bindingKind`, `bindingStatus.kind` (`active`/`ha_disabled`/ + `orphaned`/`unverified`), `DevItem.entities` — все существуют в `src/devices.ts`, + `src/ha-binding-status.ts` с ровно теми значениями, которые ТЗ им приписывает. + - Идентификаторы тестовых артефактов из плана и AC — все существующие, + не выдуманные: `test/device-presentation.test.mjs` (1092 строки), + `demo/smoke_wireless_controller_parity.mjs` (162 строки), + `scripts/mutation-gate.mjs` содержит мутанты `controller-availability-follows-target`, + `wireless-controller-loses-filtered-target-role`, + `wireless-controller-preview-drops-sibling-markers` (используются также в + `test/fixtures/device-presentation-decisions.mjs` для S03/S05/S07). + - `docs/DEVICE-PRESENTATION.md` строка S05 сегодня буквально гласит «цель + работает, controller не имеет live entity → faded controller» — ТЗ §9 + корректно называет её на разделение. + - `docs/USER-GUIDE.ru.md:979` и таблица строка 1000 сегодня документируют + «отсутствуют» (нулевой roster) как один из триггеров бледного маркера — + это ровно текст, который реализация обязана сузить; ТЗ §9 называет этот + документ в списке правок, не давая финальной формулировки (корректно — + формулировка не продуктовый факт, а редактура канона). +7. Проверено соответствие обязательного чек-листа `docs/specs/README.md` + («Обязательные release-артефакты номерного ТЗ») — все четыре пункта закрыты + разделами §9 и §15 ТЗ. +8. Проверено, что коммит на ветке ровно один, docs-only, класс C по AGENTS.md + (не требует ревью само по себе, но здесь — часть DoD этапа spec), трейлеры + корректны для docs-only коммита. + +Гейты не гонялись: этап — ревью ТЗ, продуктового кода в диффе нет (класс C, +только `docs/**`). Раздел «чего не проверял» — ниже. + +## Находки + +Нет. Ни одной High- или Medium-находки. + +Проверены типичные классы дефектов спек-ревью и не обнаружены: + +- **Догадка, выданная за факт.** Не найдена: единственный продуктовый вопрос + (эмпти-roster active device = доступен?) задан аналитиком и решён владельцем + до старта написания ТЗ (комментарии от 12:37 и 12:42). §16 ТЗ содержит + явный блок «принято предположительно, поменять свободно» ровно для + технических, не продуктовых решений (расположение предиката, отсутствие + нового enum, ID decision trace) — как и требует §7.1. +- **Отсутствие открытого вопроса при сложной задаче.** Вопрос был; он снят + корректно, до, а не во время написания ТЗ. +- **Несуществующие идентификаторы/файлы в AC и плане.** Все имена функций, + тестовых файлов и mutation ID существуют в дереве репозитория (см. выше). +- **Расхождение с каноном подсистемы.** Диагноз и предлагаемое правило не + противоречат ни одному существующему решению таблицы S01–S09; #251 и #274 + явно сохранены как негативные тесты (AC3, AC4). +- **Нарушение SCOPE.md.** Изменение — узкое исправление существующего J1/J3 + сценария, не расширяет функциональность и не вводит новый визуальный + элемент (§5 «Не входит» явно запрещает новый badge/glyph/pulse/цвет/текст). +- **Единое число, два источника.** Неприменимо: изменение касается только + availability/цвета подложки, не вводит и не дублирует числовое значение. +- **Отсутствие раздела §7.1.** Все обязательные разделы присутствуют: + сценарий и персона (§1), что человек увидит до/после (§2), проблема (§3), + скоуп/не-скоуп (§5), контракт поведения (§6), UX (§7), модель + данных/миграция (§8), i18n (§9), AC1–AC9 с доказательствами (§10), план + автотестов (§11), перф/безопасность (§12), риски (§13), откат (§14), + release-артефакты (§15). +- **Владельцу вынесен технический вопрос под видом продуктового.** Не найдено: + единственный заданный вопрос («считать ли активный device-binding без + сущностей доступным») — ровно продуктовый по определению §7.1 (что + человек видит). + +## Что проверено и корректно + +- Формат документа, нумерация разделов, наличие всех обязательных пунктов + §7.1 PROCESS.md. +- Трек задачи (полный) обоснован названным критерием, а не молчаливым + умолчанием. +- Диагноз причины (§3 ТЗ) — подтверждён построчным чтением + `controllerAvailability()` и `resolveHaBindingStatus()`, соответствует + фактическому коду один в один. +- Предикат «active physical device binding» (§6.1) — реализуем на + существующих полях (`bindingKind`, `bindingStatus.kind`, `d.virtual`), не + требует новых данных. +- Матрица §6.2 непротиворечива и покрывает все девять комбинаций + binding×roster×target из отдельного анализа, включая явно исключённые + virtual/ha-disabled/orphaned строки. +- Скоуп/не-скоуп (§5) точно очерчивает границу: entity-bound markers, + registry-как-online-для-непустого-roster, новый visual vocabulary — всё + явно исключено, что закрывает главный риск (широкое ослабление контракта + #251). +- AC1–AC9 каждый называет способ доказательства через существующий или явно + спланированный тестовый механизм (unit, production-bundle smoke, + mutation-gate, diff audit), ни один не оставлен голословным. +- Release-артефакты (§15) и обязательный чек-лист `docs/specs/README.md` + закрыты: changelog RU/EN, список затронутой пользовательской документации, + явное заявление об отсутствии новых screenshot/golden baseline при условии + зелёных существующих сьютов. +- Откат (§14) описан и не требует обратной миграции данных, так как модель/ + конфигурация не меняются (§8 подтверждён отдельно). +- Ветка, коммит и трейлеры соответствуют `AGENTS.md`: `issue/318-switch-render-state`, + один docs-only коммит, `Issue: #318` + `User-Visible: no`, SHA хендоффа + (`1242a3b`) совпадает с фактическим HEAD. + +## Чего не проверял + +- **Гейты `typecheck`/`test`/`build`/`bundle:sync`/`bundle:budget`/`check-docs`** — + не гонялись. На этом этапе в диффе нет ни одного файла класса A/B/D (только + `docs/specs/**`), продуктовый код не менялся, гонять их бессмысленно: они + проверяют код, которого ещё нет. Ссылка на зелёный Validate `1242a3b1` + (https://github.com/Matysh/houseplan-card/actions/runs/33172444930) + относится к этому же SHA и подтверждает, что репозиторий в целом зелёный, + но это не подменяет проверку самого ТЗ — она сделана вручную чтением. +- **Смоки, golden, mutation-gate, invariants** — не прогонялись и не должны: + это план на этап реализации (§11 ТЗ), сейчас проверяется только + существование названных файлов/идентификаторов, не их поведение под ещё + не написанный код. +- **Финальная формулировка правок канона** (`DEVICE-PRESENTATION.md` S05, + `ARCHITECTURE.md`, `USER-GUIDE.md`/`USER-GUIDE.ru.md`, `TESTING.md`) — ТЗ + правомерно откладывает точный текст на этап реализации; проверено только, + что список затронутых документов полон и совпадает с реальными текущими + формулировками, которые придётся менять (см. «Как проверялось», пункт 6). +- **UI/браузер** — на этапе ревью ТЗ ручного тестирования нет по определению + этапа; кода для проверки не существует. + +## Унаследовано из r + +Неприменимо — это первый заход (r1), предыдущего раунда нет. + +## Вердикт + +Зелёный. Спецификация полна по §7.1, продуктовый вопрос закрыт владельцем до +написания, технический диагноз и контракт проверены построчным чтением кода +и совпадают с реальностью, скоуп/не-скоуп корректно ограничивают риск +ослабления контракта #251, AC доказуемы существующими или явно +запланированными механизмами. High: 0. Medium: 0.