Files
houseplan-card/docs/reviews/SPEC-REVIEW-594-r2.md
T
2026-09-18 19:59:37 +00:00

192 lines
19 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-594-r2
Issue: https://github.com/Matysh/houseplan-card/issues/594
Этап: ревью ТЗ (PROCESS.md §2.4), заход r2, лимит циклов 4 (полный трек — меток
`small`/`trivial` на issue нет).
## Материал раунда
- Тело issue #594 в текущем виде (создано 2026-09-18T19:37:30Z комментарием-заведением,
далее **ни разу не редактировалось** — в `gh api .../issues/594/events` нет ни одного
события `edited`; единственные события — labeled/unlabeled и два `commented`).
- `sha256` нормализованного тела на этом прогоне (из `review-prepared/prepared.json`,
сгенерировано конвейером при применении текущей метки `S4-spec-review` в 19:43:22):
`material_issue_body = 97f5a0277d2aee81abd986c24d874aa94949902428cc33bd2eb845990d48b37b`,
`material_sha = 7ce9e6437f2584198fef3e3618173a885e825044` (рабочая копия репозитория),
run_id `35387520162`, `cycle: "2"` — совпадает с заходом r2 в заголовке задачи.
- **Ключевой факт раунда: дельты с материалом r1 нет.** Комментарий Matysh 19:43:19
("Редакция ТЗ по уточнению владельца 18.09... Возвращаю на ревью ТЗ") текстуально
описывает содержимое, которое уже присутствует в теле issue с момента его создания
(К5, К6, AC11 и т. д. — сверено построчно), а не отдельную правку тела: событий
`edited` после создания нет. Значит вердикт r1 (комментарий ниже) и этот раунд
разбирают **один и тот же байт-в-байт текст**.
## Вердикт предыдущего раунда (r1) — как он найден
`docs/reviews/SPEC-REVIEW-594-r1.md` в репозитории не найден ни в одной ветке
(`git log --all --diff-filter=A -- '*SPEC-REVIEW-594*'` — пусто) и не найден на диске
CI-раннера: это ожидаемо и не является дефектом (см. преамбулу задачи — документ
некоммитнутого раунда живёт вне репозитория и не обязан переживать раунд). Материалом
для сверки служит вердикт-комментарий:
> **Вердикт: жёлтый · заход r1 · блокирующих циклов 0/4 · High: 0 · Medium: 1 → в задаче**
> (комментарий `github-actions[bot]`, 2026-09-18T19:48:40Z,
> https://github.com/Matysh/houseplan-card/issues/594#issuecomment-5735359281)
**Находка процесса (не блокирует, фиксирую по инструкции раунда):** этот комментарий не
называет ни SHA материала, ни blob тела issue, ни ссылку на артефакт с анкорным блоком
из PROCESS.md §2.10 п.1 ("блок дописывает SHA ветки, дерево материала и блоб ТЗ").
Материал пришлось восстанавливать косвенно — через отсутствие `edited`-событий в
таймлайне issue и через `prepared.json` текущего запуска. Для ревью ТЗ (в отличие от
код-ревью) SHA ветки в принципе неприменим, но blob тела — применим и его стоило бы
называть в самом вердикт-комментарии, а не только в служебном JSON конвейера.
## Закрытие раунда r1
| # | Находка r1 | Чем закрыта | Где это видно |
|---|---|---|---|
| Medium (в скоупе) | Раздел «i18n» называет только 4 новых `*.help`-ключа для подсказок групп, но не называет ключи для текста самих заголовков групп («Основное», «Заливка», «Источники», «Размеры») — а это такой же пользовательский текст через `_t()`, как и всё остальное; ни один существующий `room.*` ключ не совпадает текстом ни с одним из четырёх заголовков | **Не закрыта.** Тело issue не редактировалось ни разу с момента создания (см. «Материал раунда» выше) | Раздел `### i18n` тела issue #594, текущий текст: *«Новые ключи только на справку заголовков групп: `room.basics.help`, `room.fill.help`, `room.sources.help`, `room.sizes.help`… Существующие ключи не трогаются»* — дословно тот же текст, который цитировал r1 |
| Low: раздел «Release-артефакты» ссылается на кадр `room-card` (View), а не на диалог настроек | Снята r1 решением ревьюера с записью, повторной проверки не требует | комментарий r1 |
| Low: раздел «Проблема» не выделен явным заголовком | Снята r1 решением ревьюера с записью («закрыт предшествующим `## Аналитика`») | комментарий r1 |
Раз тело не менялось, Medium-находка объективно не может быть закрыта в этом раунде —
это не новая находка, а тот же дефект ТЗ, ещё не исправленный автором. Верификация
собственным чтением (ниже) подтверждает: находка обоснована.
### Независимая проверка находки r1 (не просто доверие)
Прочитал текущую структуру диалога, чтобы находка не осталась голословной цитатой:
- `src/editors/room-settings-dialog.ts:60` — `room.settings_section` = «Настройки
комнаты (переопределяют пространство)» сейчас заголовком накрывает **весь** блок:
заливку **и** оба источника (temp/hum). ТЗ делит этот блок на два новых заголовка
«Заливка» и «Источники» — прямой реюз `room.settings_section` для одного из двух
новых заголовков без явного решения невозможен, нужен минимум один новый ключ.
- `src/editors/room-settings-dialog.ts:93` — `room.sizes_section` = «Размеры шрифтов»
(en: «Font sizes») — по смыслу близко к предложенному заголовку «Размеры» и мог бы
быть переиспользован **явным решением**, но ТЗ этого решения не фиксирует.
- Блок «Основное» (имя + область) сегодня заголовка вообще не имеет — это четвёртый
ключ, которого нет ни в существующем коде, ни в разделе i18n ТЗ.
- Итого: минимум 1, вероятно 3–4 новых `*_title`-ключа (плюс сопутствующие `en/ru/fr/de`,
как и у `.help`), которых в разделе i18n нет ни явно, ни как решение «переиспользовать
Х». DoR §2.5 требует «i18n: ключи en + ru перечислены» — список неполон, точно так же,
как записал r1.
Вывод: находка r1 не просто актуальна, а её независимая перепроверка кода только
усиливает — реального готового реюза на 3 из 4 заголовков нет, значит это не забытая
формальность, а недостающая проектная развилка, которая по DoR обязана быть решена до
`S5-ready`.
## Унаследовано из r1 (без повторной проверки состава, только точечная сверка)
Материал идентичен, поэтому эти пункты не разбираю заново по существу — я лишь выборочно
перепроверил чтением кода несколько наиболее рискованных, чтобы не просто доверять
чужому выводу (список ниже помечен, что именно сверено сейчас):
- К1 (ключи черновика `_nameSel`, `_areaSel`, `_roomFill`, `_roomCustomFill`,
`_roomTempMin/Max`, `_roomTempSrc/_roomHumSrc`, `_roomNameScale`, `_roomLabelScale`) —
унаследовано с r1, **не сверял повторно** (не риск для i18n-находки).
- `_renderRoomSource` — единственный потребитель — унаследовано с r1.
- К3 (`hp-color-opacity`, событие `hp-color-opacity-change`) — **сверено повторно**:
`grep` подтверждает событие и его контракт `{color, opacity}` используется тем же
образом в `room-settings-dialog.ts:80` и в остальных потребителях компонента
(`decor-image-editor.ts`, `houseplan-editor-runtime.ts`). Совпадает с выводом r1.
- Шесть вариантов заливки (АС/UX) — **сверено повторно**: `ROOM_FILL_MODES` в
`src/logic.ts:932` содержит 5 значений (`none, lqi, light, temp, custom`), плюс код
диалога добавляет вариант `''`/`fill.inherit` первым (`room-settings-dialog.ts:62`) —
итого 6, как заявляет ТЗ. Подтверждено.
- AC7: golden-сцены `room-temperature-dialog-{desktop-en,mobile-ru}` — **сверено
повторно**: `demo/golden/matrix.mjs:1016-1021` объявляет обе сцены с
`dialog: 'room-temperature'`, а `demo/golden/harness.mjs:1740-1767` для этого типа
сценария вызывает `card._openRoomEdit(room)` и ищет `hp-dialog.roomdialog` — это
ровно тот же диалог, который рендерит `renderRoomSettingsDialog` (класс `roomdialog`,
`room-settings-dialog.ts:34`). Заявленные эталоны действительно покрывают
редактируемую форму, а не отдельный мини-диалог с похожим именем.
- AC8/тест `editor-dialog-modules.test.mjs` — файл существует
(`test/editor-dialog-modules.test.mjs`), `INITIAL_VIEW_GZIP_CEILING` определён в
`scripts/bundle-budget.mjs:294` — **сверено повторно**, унаследованный вывод r1 верен.
- `hp-help` и паттерн `.help(.aria)` — унаследовано с r1, **не сверял повторно**.
- Техническая развилка стилей панель-строка / карточка-теги (К5, `cardStyles` как
синхронный граф, `houseplan-card.ts:13711`) — унаследовано с r1, не риск для
i18n-находки, не пересматриваю.
- Согласие ТЗ с обоими решениями владельца от 18.09 (набор+диалог одним issue; стили
панели не трогаются в этом шаге) — унаследовано с r1.
- Обе Low-находки r1 (снятые с записью) — унаследованы как закрытые, не пересматриваю.
Источник наследования: комментарий-вердикт r1,
https://github.com/Matysh/houseplan-card/issues/594#issuecomment-5735359281, материал —
тело issue #594, идентичное текущему (см. «Материал раунда»).
## Находки этого раунда
### Medium (в скоупе задачи, унаследована из r1, не закрыта)
**Раздел «i18n» ТЗ не называет ключи для текста заголовков четырёх новых карточек-групп**
(«Основное», «Заливка», «Источники», «Размеры»), хотя раздел «Что человек увидит»
и «UX» прямо вводят эти подписи как видимый пользователю текст, идущий, как и всё
остальное в диалоге, через `_t()`. Ни один существующий ключ `room.*` не покрывает все
четыре напрямую (см. «Независимая проверка находки r1» выше — `room.settings_section`
накрывает сразу два новых заголовка, `room.sizes_section` близок к одному, у «Основное»
реюза нет вовсе). DoR §2.5 требует полный список i18n-ключей en+ru до перехода в
`S5-ready` — список сейчас неполон.
**Воспроизведение:** открыть раздел `### i18n` тела issue #594 — там 4 ключа `*.help` (+
`.aria`), и не более. Раздел `### Контракт поведения`, пункт «После:» и раздел `### UX`
называют четыре подписи групп текстом, которого в i18n-разделе нет.
**Правка (описана уже r1, повторяю, так как не выполнена):** добавить в раздел i18n
явный список из 4 ключей заголовков (например `room.basics_title`/`room.fill_title`/
`room.sources_title`/`room.sizes_title`) для en/ru/fr/de **или** явно решить для каждого
заголовка «переиспользуем ключ X» — в том числе зафиксировать, что `room.settings_section`
для двух новых заголовков не подходит без переименования/расщепления, а `room.sizes_section`
можно оставить как есть только если текст «Размеры шрифтов» устраивает как заголовок
карточки «Размеры» (сейчас это не решено явно).
## Что проверено и корректно
- Материал раунда установлен точно (пустая дельта подтверждена таймлайном issue, а не
предположением).
- Находка r1 перепроверена независимым чтением кода, а не просто процитирована.
- Пять пунктов из унаследованного списка r1 сверены повторно точечно (см. выше) и
подтвердились без расхождений.
- ТЗ по-прежнему формально полно по остальным разделам §7.1 (сценарий, что человек
увидит, скоуп/не-скоуп, контракт К1–К7, UX, модель данных, AC1–AC11 с доказательством,
план автотестов, риски, откат, release-артефакты) — здесь не пересматриваю состав,
так как дельта их не касается и r1 их уже принял.
## Чего не проверял
- Полный повторный аудит AC1–AC11, К1–К7, рисков и release-артефактов «с нуля» — дельта
нулевая, они наследуются из r1 согласно PROCESS.md §2.10 п.4 (перепроверяются только
AC, которые задевает дельта; дельты нет, кроме отсутствия правки самой находки).
- Гейты кода (typecheck/test/build/golden/смоки) — этап spec, кода ещё нет, они
неприменимы к ревью ТЗ.
- Не связывался с владельцем и не запрашивал новых продуктовых уточнений: находка
этого раунда техническая (список i18n-ключей — «то, чего пользователь не наблюдает»
до факта показа формы; сами названия групп уже зафиксированы в ТЗ как факт, не как
открытый продуктовый вопрос), значит она решается автором и ревьюером, не владельцем.
## Вывод
Дельты со времени r1 нет: находка Medium не закрыта, потому что тело issue не
редактировалось. Верхнеуровневый разбор ТЗ сокращён по PROCESS.md §2.10 (дельта пуста),
но находка перепроверена по существу, а не унаследована слепо. Возврат автору для правки
раздела i18n; при следующем заходе ревью снова ограничится дельтой, если правка не
заденет ничего кроме этого раздела.
**Вердикт: жёлтый · заход r2 · блокирующих циклов 2/4 · High: 0 · Medium: 1 → в задаче**
---
<!-- material-anchors: сгенерировано конвейером (#414) -->
## Материал раунда
- Ветка: `dev`, коммит `7ce9e6437f25` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
- Дерево материала: `257277214219bb8aac1bf3546c47cebe7615b709`
```
git log --all --format='%H %T' | grep 257277214219
```
- Тело issue: `97f5a0277d2aee81abd986c24d874aa94949902428cc33bd2eb845990d48b37b`
- Вердикт конвейера: `yellow` · High 0