Files
houseplan-card/docs/reviews/SPEC-REVIEW-598-r2.md
T
2026-09-19 14:19:13 +00:00

194 lines
22 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-598-r2
**Issue:** https://github.com/Matysh/houseplan-card/issues/598
**Заголовок:** Три оставшихся диалога настроек на общий набор контролов: Пространство, Общие,
Устройство (шаг 3 эпика #591)
**Этап:** ревью ТЗ (PROCESS.md §2.4)
**Заход:** r2 · блокирующих циклов израсходовано 1 из 4
**Материал:** тело issue #598, раздел `## ТЗ`, снято `gh issue view 598 --json body` на момент
чтения 2026-09-19 (редакция текста — r3 по собственной нумерации автора; раунд ревью — r2, так
как редакции r2→r3 прошли под `blocked` без нового ревью). Комментариев к issue — 4: вердикт
конвейера r1, ответ автора на M1 (с открытым вопросом), ответ владельца, финальный ответ автора
со снятием `blocked` и заявкой `S4-spec-review`.
## Скоуп ревью r2
По PROCESS.md §2.10 предмет повторного раунда — дельта, а не задача целиком. Прежний вердикт
(SPEC-REVIEW-598-r1.md, `docs/reviews/`) — единственная находка M1, Medium, в скоупе. Материал
того раунда объявлен в его блоке «Материал раунда»: ветка `dev`@`958ab36652eb`, дерево
`232dd22abb22fc04ea01c124ac4332a6060a4fc8`, блоб тела issue
`aee54691f0fa3651f53c32dcb2934b5d0ebb983714e8c297783696b476976331`. Код по issue не писался
(веток `issue/598-*` нет, `git branch -a | grep 598` — пусто, HEAD на `ac1d25a0` — это как раз
коммит публикации `SPEC-REVIEW-598-r1.md`, `git status` чист), поэтому дельта — только текст
тела issue между r1 и текущей редакцией.
Готового постраничного диффа тела issue GitHub не отдаёт (правки — не отдельные ревизии API, а
редактирование одного и того же issue body), поэтому дельта восстановлена по авторской записи:
комментарий «Ответ на жёлтый вердикт r1» построчно называет, что изменилось (М1, вторая находка
про словарь `gs.hint`, пересчёт счётчиков), а текущее тело issue сверено с этим перечнем построчно
— см. «Как проверялось» ниже. Это тот же метод доказательства, что использует сам конвейер для
git-дельты: не гадание, а сверка заявленного изменения с итоговым текстом.
Разбор остаётся по дельте: рёбейз/смена контракта/новая подсистема неприменимы к текстовому ТЗ,
объём дельты (одна находка + одно сопутствующее наблюдение автора) несравним с объёмом всего ТЗ.
Проверке заново подлежат ровно те разделы, которых касается дельта: К4, К5, УX-таблицы «Общие» и
«Устройство», раздел i18n со счётчиками, риск №4, AC4, AC5. Остальные разделы (§7.1 полностью,
К1–К3/К6–К8, AC1–AC3/AC6–AC11, скоуп/не-скоуп, классы риска §2.6, план автотестов, откат,
release-артефакты) дельта не трогает — они наследуются из r1 (раздел ниже).
## Как проверялось
1. Прочитано текущее тело issue #598 целиком (`gh issue view 598 --json body`, 312 строк) и все 4
комментария (`gh issue view 598 --json comments`).
2. Открыт архивный `docs/reviews/SPEC-REVIEW-598-r1.md` — проверено, что находка M1 сформулирована
именно так, как её описывает текущий раздел «Закрытие раунда r1» ниже (сверка дословная).
3. Построчно сверены места, где дельта обязана была появиться, с текущим текстом ТЗ:
- К5 (новый контракт) присутствует и называет оба сообщения о состоянии поимённо со ссылкой на
решение владельца;
- УX-таблица «Общие настройки», строка «Солнце», явно оставляет `gs.sun_missing` callout'ом; УX
«Устройство на плане» явно называет карточку («Действие по нажатию»), где остаётся callout'ом
`marker.run_target_gone`, — то есть седьмое пояснение из r1-находки больше не висит без места;
- раздел i18n предметно: «Итого 24 ключа, 96 строк» вместо прежних 26/104; таблица разбивки
12+12 ключей × 4 языка = 48+48 строк сходится арифметически (проверено умножением, не
переписано на слово);
- список «переиспользуются и не удаляются» в i18n явно включает и `gs.sun_missing`, и
`marker.run_target_gone` — они не попадают ни в один список переносимых ключей;
- AC5 добавлен, доказательство — блок в смоках «Общих» и «Устройства» с фикстурой без
`sun.sun` и черновиком с несуществующей целью, страж — новый мутант
`state-callout-hidden-under-help`;
- риск №4 переписан под этот же риск явно («соблазн спрятать предупреждение заодно... запрещено
К5 и сторожится мутантом»);
- нумерация AC — пересчитана таблица ТЗ: AC1…AC11, встроен новый AC5, дальше сдвинуто на один
без пропусков и дублей (сверено построчно, не на слово автора).
4. Отдельно проверено новое наблюдение автора, не бывшее находкой r1: перенос `gs.hint` из
`src/i18n/support/*.json` в основной каталог как `gs.card_fills.help`.
`grep -rn "gs.hint\|gs\\.hint" src/` и чтение `src/editors/general-settings-dialog.ts` /
`src/i18n/support/*.json` подтверждают заявленное — ключ реально живёт в `support/*.json` и
читается через `supportT(...)`, а `_help()` действительно резолвит `${string}.help` через
основной `_t`. Значит перенос текста между словарями, который называет ТЗ, — не выдумка, а
реальное расхождение путей чтения; `test/i18n-dead-keys.test.mjs` реально существует и
действительно сливает оба словаря (файл присутствует в дереве), так что заявление «оставленная
копия покраснит его» проверяемо, а не голословно.
5. Терминология «карточки-группы» — уже используется `docs/USER-GUIDE.ru.md:572` для диалога
комнаты (#594); r1 это подтвердил, дельта термин не меняет — унаследовано.
6. `git branch -a`, `git log --oneline -3`, `git status` — подтверждают отсутствие кода и то, что
HEAD стоит ровно на коммите публикации r1-документа; материал для код-ревью по этому issue не
существует, гейты (typecheck/test/build) неприменимы на этапе ревью ТЗ, как и в r1.
## Закрытие раунда r1
| Находка r1 | Чем закрыта | Где это видно |
|---|---|---|
| M1 (Medium) — судьба `marker.run_target_gone` не решена; счётчик i18n «7 пояснений» расходится с 6 явно поимёнными парами «карточка → текст» | Автор задал продуктовый вопрос владельцу (обязателен, т.к. решение 18.09 «под «?» уезжает всё» — продуктовое, распространять ли его на предупреждения — тоже продуктовый вопрос, а не только технический выбор варианта а/б, которые оба предложил r1); владелец ответил в комментарии: оба сообщения остаются видимыми callout'ами. ТЗ переписано: добавлен К5, AC5, УX-таблицы обеих форм явно называют карточку/место, где остаётся callout, риск №4 и мутант `state-callout-hidden-under-help` добавлены, счётчик i18n пересчитан на 24 ключа/96 строк | К5 (строка «Сообщения о состоянии остаются на виду»); AC5 в таблице критериев; УX-таблица «Общие настройки» строка «Солнце» и «Устройство на плане» строка «Действие по нажатию»; раздел i18n «Итого 24 ключа, 96 строк»; раздел «Риски» пункт 4 |
| Сопутствующее наблюдение автора (не было находкой r1, вскрыто при разборе M1) — `gs.hint` читается из `support/*.json`, а не из основного словаря; перенос под «?» — это перенос ключа между словарями, а не только разметки | Явно описано отдельным разделом «`gs.hint` лежит в другом словаре»; в i18n-разделе прямо сказано: переезжает как `gs.card_fills.help`, копия в support удаляется во всех четырёх локалях, `test/i18n-dead-keys.test.mjs` покраснит при забытой копии | Раздел «`gs.hint` лежит в другом словаре» в «Аналитике»; раздел i18n, абзац «Отдельно: `gs.hint` переезжает...» |
Оба пункта закрыты текстом ТЗ, а не заявлением «сделано»: место, счётчик и страж названы конкретно
и проверяемы по самому тексту, без необходимости угадывать поведение реализации (ровно то, чего не
хватало для AC4 в r1).
## Унаследовано из r1
Без повторной проверки приняты выводы `docs/reviews/SPEC-REVIEW-598-r1.md` (материал: `dev`@
`958ab36652eb`, дерево `232dd22abb22fc04ea01c124ac4332a6060a4fc8`), поскольку дельта r1→r2 их не
затрагивает:
- полнота обязательных разделов §7.1 (сценарий, что человек увидит, проблема, скоуп/не-скоуп,
контракт поведения, УX, модель данных и миграция, i18n, AC, план автотестов, риски, откат,
release-артефакты) — дельта не удаляла и не переименовывала ни один раздел, только правила К4,
добавила К5 и AC5, пересчитала i18n;
- К1–К3, К6–К8 — запись в те же ключи, поведение сохранения/отмены, `hp-color-opacity`, классы-опоры
`.srcrow`/`.dispsection`/пр., клавиатура/44px, граф загрузки — не упомянуты дельтой, текст не
менялся;
- AC1–AC3, AC6–AC11 (нумерация до AC5 не сдвигается, после — сдвигается на один без потери
содержания, проверено построчно в п.3 «Как проверялось») — доказательства и способы покраснения
идентичны r1;
- скоуп/не-скоуп — идентичен, сверен построчно на этапе r1 с архивным `SPEC.md` эпика #591 и с
#594 — дельта эту границу не трогает;
- 11 golden-сцен AC8 (было AC7 в r1) — тот же список имён, дельта не добавляла и не убирала сцены;
- классы риска §2.6 — не переписывались;
- терминология «карточки-группы» (USER-GUIDE.ru.md:572) и минимум 44 px (TOUCH-SUPPORT.md) — не
переписывались;
- существование примитивов набора (`form-kit.ts`: `formCard`, `formRow`, `segmented`, `colorRow`) и
факт, что `hpf-switch` в коде не существует и правильно помечен «принято предположительно», —
дельта эти утверждения не касается.
## Находки
Не найдено. Дельта закрывает M1 полностью и по существу (не декларативно): продуктовая часть
вопроса ушла владельцу и получила прямой ответ, техническая часть (счётчики, место словаря)
решена автором самостоятельно и корректно, с проверяемыми доказательствами. Новых догадок,
выданных за факт, дельта не вносит — оба новых утверждения (перенос словаря, арифметика счётчиков)
проверены по коду и по самому тексту таблиц, а не приняты на слово.
## Что проверено и признано корректным
- М1 закрыт: `marker.run_target_gone` явно назван callout'ом карточки «Действие по нажатию»,
`gs.sun_missing` — callout'ом карточки «Солнце»; ни один не участвует в переносе под «?»; AC4
(«абзацев-пояснений... не осталось») теперь непротиворечив относительно AC5 («сообщения о
состоянии остались видимыми»), поскольку ТЗ явно развело термины «пояснение» и «сообщение о
состоянии» и использует слово «callout» только для второго — код-ревьюеру не придётся гадать,
что считается нарушением AC4.
- Продуктовый вопрос действительно был продуктовым (что человек видит — предупреждение или скрытая
подсказка) и действительно ушёл владельцу, а не решён автором за него; технический побочный
вопрос (словарь) автор решил сам, как и предписывает §7.1 — граница между двумя видами вопросов
соблюдена корректно.
- Счётчики i18n пересчитаны верно и согласуются с комментарием автора «было 26/104, стало 24/96» —
проверено умножением по таблице, а не переписано на слово.
- `gs.hint`/`supportT`/`_help()`/`test/i18n-dead-keys.test.mjs` — реальные пути в коде, наблюдение
автора не является отвлечённым утверждением.
- Материал раунда r1 (SHA `958ab36652eb`, дерево, блоб тела issue) не осиротел: `dev` не двигался
вперёд относительно r1 непредвиденным образом, HEAD рабочей копии — коммит публикации того же
документа; отдельная реставрация по дереву/блобу не потребовалась.
## Чего не проверял
- Не проверял `fr`-локаль на реальные значения строк (унаследовано из r1 — там же не проверялось
предметно, только совпадение счётчика «4 языка» с существующими словарями `en/ru/de/fr`).
- Не сверял архивный `SPEC.md` эпика #591 построчно — он не входит в это репо (не найден ни по
`find . -iname "SPEC.md"`, ни в файловой системе с иным путём), это внешний присланный документ;
ТЗ и r1, и текущая редакция сознательно берут из него только раскладку, отклонённые части (смена
поведения, компас, инлайн-цвет и т.д.) не входят в скоуп и не требуют сверки.
- Не запускал `npm test`/`npm run typecheck`/`npm run build` — кода по issue нет (ветки `issue/
598-*` не существует), гейты неприменимы на этапе ревью ТЗ; они станут предметом код-ревью.
- Не оценивал будущую формулировку `docs/USER-GUIDE.ru.md` для новой раскладки трёх диалогов — этот
документ обновляется на этапе кода (Release-артефакты ТЗ это явно называют), сейчас сверялась
только терминологическая преемственность («карточки-группы»), не текст будущей правки.
## Вердикт
Единственная находка предыдущего раунда закрыта по существу: продуктовый вопрос решён владельцем,
техническое наблюдение — автором, оба с явными, проверяемыми следами в тексте ТЗ (К5, AC5,
УX-таблицы, счётчики i18n, риск №4, новый мутант). Дельта не вносит новых High или Medium находок и
не разрушает ни один вывод r1: наследуемые разделы не затронуты, а точки соприкосновения с дельтой
(AC4/AC5, i18n-таблица) проверены заново и непротиворечивы. ТЗ готово к разработке.
`Вердикт: зелёный · заход r2 · блокирующих циклов 1/4 · High: 0 · Medium: 0`
---
## Материал раунда
- Ветка: `dev`, тот же коммит, что и в r1 — `958ab36652eb` (кода по issue #598 не появлялось между
раундами); рабочая копия ревью — `ac1d25a08cb6da1e4154e857df761504a7f79d1d` (коммит публикации
`SPEC-REVIEW-598-r1.md`).
- Тело issue снято `gh issue view 598 --repo Matysh/houseplan-card --json body` 2026-09-19,
312 строк — предмет этого раунда; официальный sha256 нормализованного тела для якоря пишет
конвейер публикации, как и в r1 (issue #414), самостоятельный расчёт здесь не приводится во
избежание расхождения метода нормализации с конвейером.
- Комментарии issue на момент ревью: 4 (`gh issue view 598 --json comments` → `length: 4`) —
вердикт r1, ответ автора (M1 + открытый вопрос), ответ владельца, финальный ответ автора.
---
<!-- material-anchors: сгенерировано конвейером (#414) -->
## Материал раунда
- Ветка: `dev`, коммит `ac1d25a08cb6` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
- Дерево материала: `d80ad22ec697829c20bd27b1a0cd5bda4d600e55`
```
git log --all --format='%H %T' | grep d80ad22ec697
```
- Тело issue: `a81e7c46b347ae3eb2a0de35e30606c335c901733d52a04e1019a937a6d737fb`
- Вердикт конвейера: `green` · High 0