16 KiB
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 для
пользовательской терминологии.
Как проверялось
- Прочитан
docs/SCOPE.md— задача закрывает J1 («что происходит сейчас») и J3 («быстрое очевидное действие»); ложный сигнал недоступности прямо противоречит J1. - Прочитаны
AGENTS.md,PROCESS.md§1–2.4, §4, §5, §7.1–7.3 — формат документа, обязательные разделы, бюджет циклов, критерий полного трека. - Прочитано тело issue #318 и все 4 комментария: заявка → анализ аналитика с продуктовым вопросом → решение владельца → хендофф автора ТЗ. Продуктовый вопрос был ровно один, и он закрыт до старта этого ревью.
- Прочитан весь файл ТЗ
docs/specs/318-empty-controller-roster.md(295 строк) целиком, раздел за разделом на соответствие §7.1. - Прочитаны канонические документы:
docs/DEVICE-PRESENTATION.md(таблица решений, строки S03–S09),docs/ARCHITECTURE.md(цитаты «Yellow means working» из issue подтверждены как существующий канон),docs/USER-GUIDE.ru.md(раздел 12 «Визуальные состояния устройств», строки 958–1004 — текущая документированная формулировка, которую ТЗ обязано будет уточнить в коде). - Сверены с реальным кодом все технические утверждения диагноза (§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 называет этот документ в списке правок, не давая финальной формулировки (корректно — формулировка не продуктовый факт, а редактура канона).
- Проверено соответствие обязательного чек-листа
docs/specs/README.md(«Обязательные release-артефакты номерного ТЗ») — все четыре пункта закрыты разделами §9 и §15 ТЗ. - Проверено, что коммит на ветке ровно один, 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/**), продуктовый код не менялся, гонять их бессмысленно: они проверяют код, которого ещё нет. Ссылка на зелёный Validate1242a3b1(https://github.com/Matysh/houseplan-card/actions/runs/33172444930) относится к этому же SHA и подтверждает, что репозиторий в целом зелёный, но это не подменяет проверку самого ТЗ — она сделана вручную чтением. - Смоки, golden, mutation-gate, invariants — не прогонялись и не должны: это план на этап реализации (§11 ТЗ), сейчас проверяется только существование названных файлов/идентификаторов, не их поведение под ещё не написанный код.
- Финальная формулировка правок канона (
DEVICE-PRESENTATION.mdS05,ARCHITECTURE.md,USER-GUIDE.md/USER-GUIDE.ru.md,TESTING.md) — ТЗ правомерно откладывает точный текст на этап реализации; проверено только, что список затронутых документов полон и совпадает с реальными текущими формулировками, которые придётся менять (см. «Как проверялось», пункт 6). - UI/браузер — на этапе ревью ТЗ ручного тестирования нет по определению этапа; кода для проверки не существует.
Унаследовано из r
Неприменимо — это первый заход (r1), предыдущего раунда нет.
Вердикт
Зелёный. Спецификация полна по §7.1, продуктовый вопрос закрыт владельцем до написания, технический диагноз и контракт проверены построчным чтением кода и совпадают с реальностью, скоуп/не-скоуп корректно ограничивают риск ослабления контракта #251, AC доказуемы существующими или явно запланированными механизмами. High: 0. Medium: 0.