docs: review document for #210

Issue: #210
User-Visible: no
This commit is contained in:
claude[bot]
2026-08-19 22:26:20 +00:00
parent 6c3d376b2b
commit b89456ca81
+168
View File
@@ -0,0 +1,168 @@
# Ревью ТЗ — issue #210, цикл r2
- **Issue:** https://github.com/Matysh/houseplan-card/issues/210
- **ТЗ:** `docs/specs/210-fixed-floor-card.md` (коммит `6c3d376`, ветка
`issue/210-fixed-floor`)
- **Предыдущий цикл:** `docs/reviews/SPEC-REVIEW-210-r1.md` — жёлтый,
High: 0, Medium: 1 (M1, в скоупе), Low: 1 (L1)
- **Трек:** обычный (аналитика явно исключила `small`/`trivial`; сложность
6/10, риск 6/10, метка `small` на issue отсутствует) — лимит циклов 4
- **Вердикт:** зелёный · цикл r2/4 · High: 0 · Medium: 0
## Скоуп ревью
Проверялось ТЗ `docs/specs/210-fixed-floor-card.md` в редакции коммита
`6c3d376` как артефакт этапа `S4-spec-review`, второй цикл. Задача — не
переповторить r1 целиком, а (1) убедиться, что правки по M1 и L1 сделаны так,
как обещано в комментарии автора, (2) не подтвердить это на слово, а
независимо перечитать документ целиком и код, к которому апеллирует новый
текст, и (3) заново пройти обязательные разделы §7.1 PROCESS.md и AC1…AC12
свежим взглядом, а не только смотреть на диф — чтобы не унаследовать слепое
пятно предыдущего цикла. Продуктового кода по #210 всё ещё не существует
(диапазон коммитов ветки — только документация), поэтому гейты §8 PROCESS.md
к этому циклу неприменимы, как и в r1.
## Как проверялось
1. Прочитаны `docs/SCOPE.md`, `AGENTS.md`, `PROCESS.md` целиком (в этой
сессии, без переноса контекста из r1 — ревью ТЗ и код-ревью обязаны идти
в разных сессиях по §6 PROCESS.md; здесь то же требование соблюдено для
независимости повторного цикла ТЗ).
2. Прочитано тело issue #210 и все шесть комментариев, включая аналитику,
вердикт r1 и комментарий автора о правках (`6c3d376`, «M1: … L1: …»).
3. Получен точный диф правки: `git diff 0bd6094 6c3d376 --
docs/specs/210-fixed-floor-card.md` — 12 добавленных строк, ни одной
удалённой; сверен построчно с тем, что обещано в комментарии автора и с
тем, что требовало M1/L1.
4. Прочитан файл ТЗ `210-fixed-floor-card.md` целиком заново, в текущей
редакции (337 строк), а не только изменённые фрагменты.
5. Перечитаны `docs/CONFIG-COMPATIBILITY.md` целиком и профильные разделы
`docs/UX-MODES.md` (header/tabs, строка 81: «Header in View: space tabs,
device count, zoom cluster. Nothing else.») и `docs/TOUCH-SUPPORT.md`
(canonical-tag правило) — те же документы, что и в r1, чтобы проверить,
не создал ли новый текст противоречие, которого не было в r1.
6. Прочитан `docs/USER-GUIDE.ru.md` в местах, которые ТЗ обязуется
обновить в release-артефактах: карточка card-options (строка 54, 125 —
`default_floor` уже называется «Стартовое пространство» в действующем
guide, то есть новый термин ТЗ **Initial space / Стартовое пространство**
не изобретён, а взят из текущего интерфейса) и раздел «Несколько карточек
и стартовые пространства» (строки 1327-1341) — подтверждает, что именно
это описание (`default_floor` как единственная защита) ТЗ обязано
уточнить в §15, и это уже учтено (не новая находка, ещё в r1).
7. Проверено соответствие нового текста коду:
- `src/editor.ts` (`_valueChanged`, объединение через `{ ...this._config,
...ev.detail.value }`) — подтверждён паттерн, на который ссылается M1
r1 («никакого существующего прецедента явной зачистки пустого поля
нет»). Новый текст §6.2 закрывает именно этот пробел явным требованием
«удалить собственный ключ `floor` из выдаваемого card config целиком»,
а не полагаться на то, что пустая строка сама попадёт в уже описанный
invalid-путь.
- Существующие смоки `demo/smoke_nav_persist.mjs`, `demo/smoke_kiosk.mjs`
присутствуют в репозитории; `demo/smoke_fixed_floor.mjs` — нет, как и
ожидается по плану тестирования (§13): новый смок создаётся в
реализации, а не сейчас.
8. Проверено, что новый §9.1 «i18n» не дублирует и не противоречит
существующим требованиям §9 (invalid-state accessibility) и §6.2 (GUI
labels) — он их резюмирует под отдельным заголовком, не вводя новых
требований к продукту.
9. Код не запускался, гейты не прогонялись — на этапе ревью ТЗ продуктового
кода нет, как и в r1 (PROCESS.md §8 относит гейты к код-ревью).
## Проверка правок по M1 и L1
### M1 (было Medium, в скоупе) — закрыто
Ровно в заявленном месте (§6.2, после абзаца про dropdown/textbox fallback)
добавлено:
> Выбор «не закреплять» обязан удалить собственный ключ `floor` из выдаваемого
> card config целиком. GUI не записывает `floor: ''` или `floor: null`: эти
> значения намеренно остаются невалидными для явно заданного YAML, а
> отсутствие свойства возвращает legacy navigation согласно §6.1.
Это прямо снимает найденное в r1 противоречие: пустой выбор GUI теперь
однозначно ведёт к обычной (legacy) навигации, а не к невалидному `floor: ''`
и, как следствие, к error state. Зеркальный пункт добавлен и в §16
(«Принятые предположения», п.8) той же формулировкой, как и просил r1. Оба
места непротиворечивы друг другу и §6.1 п.3 (`''`/`null` остаются невалидными
для **явного** YAML, что осталось неизменным и корректным — M1 просил
разграничить «GUI никогда не пишет эти значения» и «явный YAML с этими
значениями всё ещё невалиден», а не менять §6.1). AC8 («GUI … умеет очистить
`floor`») теперь однозначно проверяем: тест должен убедиться, что после
очистки ключ отсутствует в объекте конфигурации, а не равен `''`/`null`.
Находка полностью устранена, без побочных противоречий с остальным текстом.
### L1 (было Low, на решение автора) — закрыто
Добавлен отдельный подраздел **§9.1. i18n** сразу после §9 (invalid-state
контракт), формально выполняющий требование §7.1 PROCESS.md об отдельном
разделе i18n. Содержание не вводит новых по существу требований — оно
называет два конкретных файла (`en.json`/`ru.json`), явно запрещает зашитые
рантайм-строки и привязывает термин к уже принятому «space / пространство» —
то есть закрывает найденный формальный пробел, не расширяя скоуп.
## Заново проверенные разделы (не только диф)
- **Обязательные разделы §7.1 PROCESS.md** — по-прежнему все присутствуют, с
добавлением отдельного i18n-подраздела структура стала полнее, чем в r1.
- **AC1…AC12** — перечитаны заново; ни один не изменился текстом со времени
r1, добавление в §6.2/§16 делает AC8 более однозначным (см. M1 выше), не
ослабляя и не меняя ни один AC.
- **Непротиворечивость нового текста остальному документу** — §6.1 (типы и
invalid-список), §9 (когда рендерится error state), §10 (fixed instance не
очищает и не мигрирует nav record) и §16 п.6 (invalid `floor` не
откатывается к `default_floor`) не пересекаются и не конфликтуют с новым
текстом об удалении ключа при очистке GUI: очистка через GUI — это
отсутствие `floor`, а не невалидное значение, поэтому она не проходит через
invalid-ветку вовсе, что и было целью правки.
- **SCOPE.md** — правка не меняет ни персону, ни поверхность, ни объём
видимого изменения по сравнению с r1; продуктовая часть контракта
по-прежнему исходит от владельца («Технические детали решаются свободно на
ревью»), а не является догадкой автора, выданной за факт.
- **Открытые продуктовые вопросы** — отсутствуют, как и в r1; оба
устранённых пункта были техническими уточнениями формулировки, не
продуктовыми развилками, и не требовали обращения к владельцу.
Новых находок — ни High, ни Medium, ни Low — при независимом перечтении
целиком не появилось.
## Проверено и признано корректным
Всё, что было проверено и признано корректным в r1 (причинная цепочка §3/§7,
структура документа, соответствие `docs/UX-MODES.md`, `docs/TOUCH-SUPPORT.md`,
`docs/CONFIG-COMPATIBILITY.md`, AC1…AC12, план тестирования, риски и откат),
остаётся в силе — правка `6c3d376` его не затронула ни одной строкой (диф
только добавляет текст, ничего не удаляет и не переформулирует). Дополнительно
в этом цикле подтверждено:
- точное соответствие внесённых правок тому, что было обещано в комментарии
автора (ничего не забыто, ничего лишнего не изменено походя);
- отсутствие побочных противоречий между новым текстом и остальными
разделами документа;
- термин **Initial space / Стартовое пространство** не изобретён — совпадает
с уже используемым в `docs/USER-GUIDE.ru.md:54,125` названием поля
`default_floor`.
## Чего не проверял
- **Фактическая работоспособность будущей реализации** — на этапе ревью ТЗ
продуктового кода не существует.
- **`ha-form`/`ha-selector` поведение при очистке optional select** —
по-прежнему не тестировалось эмпирически; текст ТЗ теперь однозначен
(«удалить ключ целиком»), но соответствие итоговой реализации этому
контракту — предмет код-ревью, не этого цикла.
- **`demo/smoke_fixed_floor.mjs`, `smoke_nav_persist.mjs`, `smoke_kiosk.mjs`**
не запускались — нового смока ещё нет, существующие два не относятся к
этому циклу (нет кода, который они могли бы проверить).
- Гейты `typecheck`/`test`/`build`/smoke/golden не прогонялись — раздел
неприменим на этапе ревью ТЗ (PROCESS.md §8 относит их к код-ревью).
## Итог
Оба цикла r1 (M1, L1) закрыты именно так, как было обещано, без побочных
противоречий и без сужения/расширения скоупа. Независимое повторное чтение
всего документа не выявило новых блокирующих или Medium-находок. Открытых
продуктовых вопросов нет. ТЗ готово к «Готово к разработке».
**Вердикт: зелёный · цикл r2/4 · High: 0 · Medium: 0**