Files
houseplan-card/docs/reviews/SPEC-REVIEW-317-r1.md
T
2026-08-28 13:33:25 +00:00

183 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SPEC-REVIEW-317-r1
- Issue: [#317](https://github.com/Matysh/houseplan-card/issues/317) — «Метрики под названием комнаты и тултип комнаты не показывают температуру и влажность, хотя датчики в комнате есть»
- Этап: spec (S4-spec-review)
- Заход: r1 · блокирующих циклов израсходовано 0 из 4
- Трек: полный (аналитик сам назвал критерий, который задача не проходит: «изменение затрагивает единый контракт данных сразу для подписи комнаты, тултипа и температурной заливки»)
- Артефакт ТЗ: `docs/specs/317-room-climate-placement.md` на SHA `f19ed10f` (ветка `issue/317-room-climate-placement`)
- Ревьюер: Claude (сессия ревью ТЗ), состязательно, без пояснений автора
## Скоуп ревью
Issue #317 — баг: `_roomTemp`/`_roomHum`, общие для подписи комнаты, tooltip и
температурной заливки, читают климат только из `areaClimateMap()`, которая
группирует сенсоры исключительно по HA registry `area_id`. Ручное размещение
маркера датчика в комнате House Plan (`marker.area`/`marker.room_id`) в
климатический агрегат не попадает, а у комнаты без HA Area автоматического
среднего нет вовсе. Владелец уже принял продуктовое решение по единственному
открытому вопросу (комнаты без HA Area — да, правило распространяется), поэтому
на входе в ревью открытых продуктовых вопросов не осталось.
Разбирался только этот документ: файла предыдущего раунда нет, дельта не
считается (§2.10 к первому заходу не применяется).
## Как проверялось
Ревью читает ТЗ состязательно: каждое утверждение о текущем поведении и о
существующей инфраструктуре сверено с кодом на дереве этого SHA, а не принято
на слово автора.
1. Прочитаны `docs/SCOPE.md`, `AGENTS.md`, `PROCESS.md` — трек, разделы §7.1,
лимит циклов и формат вердикта.
2. Прочитаны тело issue #317 и все комментарии, включая явное решение
владельца («да, распространяем автоматическое правило также на комнаты без
HA Area», 2026-08-28).
3. Прочитан `docs/specs/317-room-climate-placement.md` целиком.
4. Диагноз ТЗ сверен построчно с кодом:
- `src/houseplan-card.ts:11956-11968` (`_roomTemp`/`_roomHum`, gate `r.area
? this._climate().get(r.area) : null`) — подтверждает §3;
- `src/houseplan-card.ts:12093` (внешний gate `_renderRoomLabel`, блокирует
метрики area-less комнаты без `temp_source`/`hum_source`/`labelLight`) —
подтверждает §3 и требование §8;
- `src/houseplan-card.ts:11058-11068` (tooltip вызывает `_roomTemp`/`_roomHum`
без gate) — подтверждает диагноз «дефект воспроизводится сразу на трёх
поверхностях»;
- `src/houseplan-card.ts:8502` (`fill_mode: temp` читает тот же `_roomTemp`) —
подтверждает единственность резолвера;
- `src/devices.ts:1394-1478` (`areaClimateMap`) — подтверждает группировку
только по `reg.area_id || dev?.area_id`, существующий tombstone/`use_climate_temp`
механизм, `NON_AIR_RE`, `entity_category` gate — контракт §6.3 списывает их
как «сохраняются», а не выдумывает заново;
- `src/devices.ts:1056-1076` (`resolveExplicitMarkerPlacement`) и
`src/devices.ts:350-357` (`lightSourceBelongsToRoom`) — подтверждают, что
приоритет «явный marker → `room_id`+`area:null` → registry» уже существует
как паттерн для визуального размещения и света; ТЗ не изобретает новый
контракт, а переносит существующий на климат;
- `src/logic.ts:2016-2030` (`parseRoomRef`) — подтверждает формат
`space#area` / `space#@roomId`, на который ссылается §9;
- `docs/ARCHITECTURE.md:1148-1153` — текущее описание one-pass climate
совпадает с диагнозом дословно;
- `docs/USER-GUIDE.ru.md:468` и `:1194` — подтверждают, что документация уже
фиксирует нынешнее (дефектное) поведение и уже содержит прецедент
«`room_id` точнее HA-зоны» для света, на который ТЗ ссылается по аналогии.
5. Проверено существование целевой тестовой/гейт-инфраструктуры, названной в
критериях приёмки, а не выдуманной:
- `test/devices.test.mjs` уже содержит матрицу `areaClimateMap` (one-pass,
tombstone, `use_climate_temp`) — AC1 расширяет реальный файл;
- `demo/smoke_climate_once.mjs` существует и уже фиксирует «44/60 rooms» —
число в AC9 не с потолка;
- `demo/smoke_climate_temp.mjs` существует — задел для AC7;
- `scripts/mutation-gate.mjs` существует и поддерживает `--id=<mutant>` —
механизм AC10 реален;
- `docs/specs/262-readd-child-entity-after-device-delete.md` действительно
фиксирует binding-scoped tombstone contract, на который ссылается §6.2.
6. Проверены обязательные разделы ТЗ по §7.1 — все на месте (см. таблицу ниже).
7. Проверена трассируемость: issue ↔ ТЗ ссылки в обе стороны, `docs/specs/README.md`
обновлён той же строкой, ветка/трейлеры коммита (`Issue: #317`,
`User-Visible: no`) корректны для чисто документационного коммита.
Гейты (typecheck/test/build) на этом шаге не прогонялись и не должны: стадия —
ревью ТЗ, продуктовый код не менялся (коммит `f19ed10f` — только
`docs/specs/**`), unit/build ничего нового не проверили бы. Это соответствует
«гейты соразмерны задаче»: полный набор гейтов относится к код-ревью, не к
ревью ТЗ.
## Обязательные разделы §7.1
| Раздел | Есть | Где |
|---|---|---|
| Сценарий (персона, поверхность, момент) | ✅ | §1, ссылается на J1/J5 `SCOPE.md` |
| Что человек увидит до/после | ✅ | §2, без терминов реализации |
| Проблема | ✅ | §3 (подтверждённый диагноз) |
| Скоуп и не-скоуп | ✅ | §5 |
| Контракт поведения | ✅ | §§6-7 |
| UX | ✅ | §8 |
| Модель данных и миграция | ✅ | §9 (миграции нет, обосновано) |
| i18n | ✅ | §11 (новых строк нет, обосновано) |
| AC1…ACn с доказательством | ✅ | §12, для каждого назван unit/smoke/mutation/review |
| План автотестов | ✅ | §13 |
| Риски | ✅ | §14 |
| Откат | ✅ | §16 |
| Release-артефакты | ✅ | §16 |
Плюс дополнительные разделы сверх минимума (архитектура/perf §10, security/privacy
§15, явный блок принятых технических предположений §17) — это хорошо
документированное ТЗ для полного трека с реальным риском перфоманса.
## Находки
Blocking (High): нет.
В скоупе (Medium): нет.
Вне скоупа (Medium → issue): нет.
### Low (снято ревьюером с записью, правки не требуют)
1. **Терминология HA Area/HA-зона в плане документации.** ТЗ систематически
использует «HA Area», тогда как `docs/USER-GUIDE.ru.md` в основном пишет
«HA-зона» и лишь один раз (строка 1194) — «HA Area». Несогласованность уже
существует в каноне до этого ТЗ (не внесена им), новых UI-строк ТЗ не
добавляет, и §11 прямо поручает автору синхронизировать формулировку при
правке `USER-GUIDE.ru.md` в реализации. Снимаю без правки ТЗ — это
редакторская забота реализации, не пробел контракта.
2. **AC8 называет доказательством «diff audit», а не один из канонических
`unit/backend/smoke/golden`.** По содержанию это ревью кода («проверено
чтением, не исполнением»): совпадение snapshot/resolver между View и hosted
Static и отсутствие мутации config естественно проверяются чтением диффа, а
не отдельным раннером. Не считаю это находкой, требующей правки текста ТЗ —
отмечаю для код-ревьюера следующего этапа: при проверке AC8 явно указать,
что это чтение, а не автотест.
## Что проверено и корректно
- Диагноз в §3 воспроизведён по коду один в один, включая три точки отказа
(label gate, `_roomTemp`/`_roomHum`, `areaClimateMap`) — не разошёлся ни в
одной детали с деревом на SHA `f19ed10f`.
- Решение владельца по единственному продуктовому вопросу зафиксировано в
issue и корректно перенесено в §4 ТЗ дословно по смыслу.
- Контракт приоритета источников (§6.2, §7) не изобретает новый паттерн, а
переносит уже существующий в проекте прецедент точного/родительского marker
(`resolveExplicitMarkerPlacement`, `lightSourceBelongsToRoom`) на климат —
ни одно утверждение о поведении не помечено как факт без опоры на код или
канон, а там, где авторы вводят технические решения, они явно вынесены в §17
«принято предположительно, поменять свободно» и открыты для оспаривания.
Единственный продуктовый вопрос (комнаты без HA Area) был задан владельцу
именно как продуктовый вопрос — не технический вопрос, замаскированный под
продуктовый.
- Каждый AC (1–11) однозначен и указывает способ доказательства; для AC1, AC7,
AC9, AC10 целевые файлы/скрипты уже существуют в дереве, значит критерии не
ссылаются на несуществующую инфраструктуру.
- Не-скоуп (§5) явно исключает эвристику air-sensor, миграцию, новый UI,
`use_climate_temp` semantics кроме placement — граница с соседними задачами
проведена, а не подразумевается.
- Откат, release-артефакты, security/privacy покрыты и согласуются с
«никогда не удалять файл пользователя на догадке» и «одно число — один
источник» (§6, §8: label/tooltip/fill читают один и тот же `_roomTemp/_roomHum`,
что и есть образцовое соблюдение принципа единственного источника числа).
- Трейлеры коммита (`Issue: #317`, `User-Visible: no`) корректны для
docs-only коммита; `docs/specs/README.md` обновлён той же строкой.
## Чего не проверял
- Не прогонял `npm run typecheck`/`npm test`/`npm run build` — на этом шаге
нет продуктового кода для проверки (коммит правит только `docs/specs/**`);
прогон ничего не доказал бы и не входит в объём ревью ТЗ.
- Не проверял поведение реального HA-инстанса и golden/browser smokes — они
относятся к код-ревью следующего этапа, когда появится код и заявленные в
§13 команды (`node demo/smoke_climate_once.mjs` и т.д.).
- Не проверял `docs/ARCHITECTURE.md`, `docs/USER-GUIDE(.ru).md`,
`docs/TESTING.md`, оба changelog на предмет уже внесённых правок — по плану
реализации (§13, §11) они меняются в коде, а не в этом ТЗ-коммите, и их
редактирование — предмет DoD код-ревью, а не спецификации.
- Не проверял корректность будущего мутанта `--id=<new-room-climate-placement-mutant>`
— он ещё не существует, ТЗ лишь называет обязательство его завести.
## Вердикт
ТЗ технически обосновано, каждое фактическое утверждение о текущем коде и
существующей инфраструктуре подтверждено чтением дерева, единственный продуктовый
вопрос уже решён владельцем, все обязательные разделы §7.1 на месте, критерии
приёмки пронумерованы и проверяемы. Blocking-находок нет, Medium нет ни в скоупе,
ни вне скоупа. Задача может переходить в «Готово к разработке».
Вердикт: зелёный · заход r1 · блокирующих циклов 0/4 · High: 0 · Medium: 0 · Документ: docs/reviews/SPEC-REVIEW-317-r1.md