mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
@@ -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<N-1>
|
||||
|
||||
Неприменимо — это первый заход (r1), предыдущего раунда нет.
|
||||
|
||||
## Вердикт
|
||||
|
||||
Зелёный. Спецификация полна по §7.1, продуктовый вопрос закрыт владельцем до
|
||||
написания, технический диагноз и контракт проверены построчным чтением кода
|
||||
и совпадают с реальностью, скоуп/не-скоуп корректно ограничивают риск
|
||||
ослабления контракта #251, AC доказуемы существующими или явно
|
||||
запланированными механизмами. High: 0. Medium: 0.
|
||||
Reference in New Issue
Block a user