22 KiB
SPEC-REVIEW-602-r2
Issue: https://github.com/Matysh/houseplan-card/issues/602
Заголовок: Полировка редизайна диалогов пространства и устройства
Этап: ревью ТЗ (PROCESS.md §2.4)
Заход: r2 · блокирующих циклов израсходовано 1 из 4
Материал: тело issue #602, раздел ## ТЗ, снято gh issue view 602 --json body на момент
чтения 2026-09-20 (188 строк). Комментариев к issue — 5: аналитика автора, вопросы владельцу
Q1/Q2, решения владельца (со снятием blocked), вердикт конвейера r1 (жёлтый), ответ автора
«Ответ на ревью ТЗ r1».
Скоуп ревью r2
Предыдущий вердикт — docs/reviews/SPEC-REVIEW-602-r1.md, жёлтый, одна находка Medium (в скоупе)
и одна Low (снята с запиской, не требовала правки для зелёного). Материал того раунда объявлен в
его блоке «Материал раунда»: ветка dev@3701cbd (коммит 3701c7bd201d), тело issue —
блоб 345487371ab35ce7a540ebb03b9eeb09cda56792a7322d0783036edb5866f78e.
Кода по issue #602 не было и нет: git branch -a | grep -i 602 пуст, рабочая копия детачед на
a4667562 — это коммит публикации самого SPEC-REVIEW-602-r1.md, git status чист. Дельта
r1→r2 — исключительно правка текста тела issue, описанная автором в комментарии «Ответ на ревью
ТЗ r1»: (1) одно/два предложения в §6.6 про семантику «уже настроенного» radar-toggle, (2) замена
неверной пары CHANGELOG.md/docs/CHANGELOG.md на docs/CHANGELOG.md/docs/CHANGELOG.ru.md в
§10 и §16.
GitHub не отдаёт постраничный дифф тела issue, поэтому дельта восстановлена методом r1/598-r2: по заявленному автором перечню правок, сверенному построчно с текущим текстом (раздел «Как проверялось»), а не на слово.
Дельта локальна: рёбейз, смена контракта поведения, новая подсистема — неприменимы к чисто текстовому ТЗ без кода; объём правки (одно предложение + два исправленных названия файлов) несопоставимо меньше исходного ТЗ. Разбору заново подлежат ровно §6.6 (сама находка) и §10/§16 (Low); §5 «Не входит» и AC11–AC13 перепроверены постольку, поскольку новая формулировка §6.6 могла их задеть. Остальные разделы (§7.1 целиком, §1–§4, §6.1–6.5, §7–9, AC1–AC10 и AC14–AC16, план тестирования, риски, rollback, release artifacts кроме исправленной пары файлов) дельта не касается — наследуются из r1 (раздел ниже).
Как проверялось
- Прочитано текущее тело issue #602 целиком (
gh issue view 602 --json body) и все 5 комментариев (gh issue view 602 --json comments). - Открыт архивный
docs/reviews/SPEC-REVIEW-602-r1.md— сверено дословно, что находки Medium и Low сформулированы так, как их описывает раздел «Закрытие раунда r1» ниже. - §6.6 текущего тела сверено построчно с правкой, заявленной в ответе автора:
- новое предложение прямо называет обе ветки происхождения («был радар ранее объявлен вручную
или автоматически распознан») и явно фиксирует решение — toggle включён при
recognition.reason === 'saved'независимо от происхождения; - явно сказано «Нового поля происхождения и изменения алгоритма распознавания моделей нет» — это прямой ответ на вторую половину находки r1 (риск конфликта с §5 «не входит: …распознавания поддерживаемых моделей радара»).
- новое предложение прямо называет обе ветки происхождения («был радар ранее объявлен вручную
или автоматически распознан») и явно фиксирует решение — toggle включён при
- Перечитан код, на который опиралась находка r1, чтобы проверить, что новая формулировка не
создаёт новой неоднозначности и не входит в противоречие с §5:
recognizeRadar()(src/radar-editor.ts:105–124) —reason: 'saved'возвращается только когдаdevice.marker.radarуже существует и валиден (isMarkerRadarV1), независимо от того, как конфиг туда попал;reason: 'ld2450'— отдельная, более узкая ветка только для устройства без сохранённого radar-конфига, чьиmodel/имена entity подошли под эвристику. Значит новая формулировка §6.6 («для reason === 'saved'») трогает ровно случай «уже есть сохранённый конфиг любого происхождения» и не переопределяет и не расширяет ветку первичного распознаванияld2450(ещё не сохранённый радар, кнопка «Настроить» вsrc/editors/radar-section.ts:108-118остаётся как есть) — конфликта с §5 «не входит: …распознавания поддерживаемых моделей радара» нет: сам алгоритм распознавания (recognizeRadar) новой формулировкой не тронут, меняется только то, где рендерится уже распознанный/сохранённый конфиг.radarDraft()(src/radar-editor.ts:161-164, вызывается безforceManualпри открытии диалога,src/houseplan-editor-runtime.ts:7585-7587) возвращает ненулевой draft, еслиoriginal(сохранённыйdevice.marker.radar) существует — то естьd.radarуже заполнен на открытии диалога для любого устройства с сохранённым radar-конфигом, что подтверждает: без явного измененияmanualEntry/условий placement описанный r1 разрыв («форма в Main, а не toggle+inline в Additional») будет воспроизводиться при каждом открытии ровно так, как и предполагала находка r1 — реализация должна будет провести toggle-ветку через placement'additional'для этого случая; ТЗ формулирует наблюдаемый результат, а не реализацию, и это на этапе ТЗ достаточно (тот же вывод, что r1 сделал про центрирование тумблера).
- §10 и §16 сверены на точное совпадение с реальными путями:
docs/CHANGELOG.mdиdocs/CHANGELOG.ru.mdназваны в обоих местах, корневойCHANGELOG.mdбольше не упоминается; RU-changelog в §10 теперь присутствует явно. - AC11–AC13 перечитаны на предмет того, не разошлись ли они с переписанным §6.6: AC11 («Radar toggle раскрывает конфигурацию непосредственно под собой и не создаёт вторую radar-секцию выше») и AC12 («Off → On до Save восстанавливает radar draft…») текстуально не изменились и остаются верны и для «внутри сессии», и для «уже сохранённого при повторном открытии» — переписанное §6.6 не требует правки AC, потому что оба AC описывают наблюдаемое поведение toggle/draft, а не конкретный триггер его появления. AC13 (virtual/saved_unsupported) не затронут дельтой и не нуждается в правке.
git branch -a,git log --oneline -5,git status— подтверждают отсутствие кода по issue между r1 и r2 и то, что рабочая копия стоит на коммите публикации r1-документа; гейты (typecheck/test/build) неприменимы на этапе ревью ТЗ, как и в r1.
Закрытие раунда r1
| Находка r1 | Чем закрыта | Где это видно |
|---|---|---|
Medium — §6.6 не уточняла, что означает «для уже настроенного радара тумблер отображается включённым»: в рамках текущей открытой сессии диалога или для радара, сохранённого в прошлой сессии; recognizeRadar() не различает происхождение (reason: 'saved' для любого сохранённого конфига), поэтому без уточнения manually-declared и auto-recognized радары рисковали получить разное поведение произвольно |
Автор явно выбрал вариант (b) из предложенных r1 альтернатив и записал его текстом: «Для любого уже сохранённого поддерживаемого radar-конфига тумблер при каждом повторном открытии диалога отображается включённым, независимо от того, был радар ранее объявлен вручную или автоматически распознан… recognition.reason === 'saved' всегда означает включённый toggle и inline-конфигурацию под ним… Нового поля происхождения и изменения алгоритма распознавания моделей нет» |
§6.6 тела issue, третий пункт списка «Radar toggle» |
Low (снята с запиской, не требовала правки для зелёного) — §10/§16 называли несуществующую пару CHANGELOG.md + docs/CHANGELOG.md, RU-changelog не был назван |
§10 и §16 переписаны на реальную пару docs/CHANGELOG.md + docs/CHANGELOG.ru.md |
§10 «Затрагиваемые модули», последний пункт; §16 «Release artifacts», первое предложение |
Обе находки закрыты по существу, а не декларативно: Medium — явным продуктовым решением с прямым
указанием на используемый код (recognition.reason === 'saved') и явным отказом от нового поля
данных (чем предотвращён конфликт с §5); Low — точным исправлением названий файлов.
Унаследовано из r1
Без повторной проверки приняты выводы docs/reviews/SPEC-REVIEW-602-r1.md (материал: dev@
3701c7bd201d, тело issue — блоб
345487371ab35ce7a540ebb03b9eeb09cda56792a7322d0783036edb5866f78e), поскольку дельта r1→r2 их не
затрагивает:
- полнота обязательных разделов §7.1 (сценарий, до/после, проблема, scope/не-входит, контракт §6, UX-состояния §7, данные/миграция §8, i18n §9, AC1–AC16 с «Свидетелем» §11, план автотестов §12, риски §14, rollback §15, release artifacts §16) — дельта не удаляла и не переименовывала разделы;
- соответствие
docs/SCOPE.md(J4/J6, персона Home admin, поверхность — только editor-диалоги); - заземление фактических утверждений §3/аналитики в коде: фиксированные ширины
4em/5.8em,padding-right: 122px/125px, текущее расположениеuseClimateTempв карточке света, разрыв «кнопка в Additional actions → форма в Main params» для radar (два вызова_renderRadarSectionс разнымplacement) — все подтверждены чтением кода в r1, дельта эти факты не переписывает; - соответствие терминологии
docs/USER-GUIDE.ru.md(футер/dialog.unsaved, radar, climate-бейдж) и существование процитированных i18n-ключей; - touch/mobile-контракт не вводится заново — установлен в #600 (320/390/480/560/768/1280/1920,
«touch остаётся best effort»), явная метка
Touch editor: …не требуется по прецедентуSPEC-REVIEW-563-r1.md; - область задачи (4 диалога) не раздута — Room/General реально импортируют общие хелперы
toggleRow/rangeEnds/footerStatusизsrc/editors/form-kit.ts, общий CSS-баг действительно их задевает; - Q1/Q2 — обе действительно продуктовые, обе закрыты явным решением владельца,
blockedснят по факту; метки (bug,P2,polish,S4-spec-review, безsmall/trivial) согласованы с выбором полного трека; - незакрытое «Чего не проверял» из r1 (golden/скриншот-покрытие Room/General как отдельная тема, implementation-детали центрирования тумблера, EN user-guide как производный документ) — дельта этих тем не касается, статус не меняется.
Находки
Не найдено. Дельта закрывает обе находки r1 по существу: Medium — явным, проверяемым по коду
продуктовым решением без нового поля данных и без конфликта с §5; Low — точным исправлением
названий файлов. Новая формулировка §6.6 перечитана против recognizeRadar()/radarDraft() и не
создаёт новой неоднозначности: она задевает ровно случай «уже сохранён» (reason: 'saved') и не
переопределяет отдельную, более узкую ветку первичного распознавания ld2450 — конфликта с §5
«не входит: …распознавания поддерживаемых моделей радара» нет. AC11–AC13 остаются согласованными
с переписанным §6.6 без необходимости правки нумерации или текста.
Что проверено и признано корректным
- Продуктовое решение по Medium принято автором в правильной форме: не техническая деталь, а явный
выбор наблюдаемого поведения («toggle включён при
reason === 'saved', независимо от происхождения»), с явным отказом вводить новое поле данных — соответствует PROCESS.md §7.1 и не расширяет тайно скоуп §5. - Формулировка §6.6 после правки не оставляет открытого вопроса про повторное открытие диалога:
единственный оставшийся триггер старой карточки
radar.title— устройство без сохранённого radar-конфига, распознанное эвристикойld2450(первичное распознавание, вне скоупа находки). - Пара changelog-файлов в §10/§16 теперь совпадает с реальными путями и с тем, что проверяет
scripts/validate-commit-provenance.mjs:64. - Материал раунда r1 не осиротел: между r1 и r2 в
devне появлялось кода по issue #602, рабочая копия ревью стоит на коммите публикацииSPEC-REVIEW-602-r1.md— отдельная реставрация дерева не потребовалась.
Чего не проверял
- Наследую нетронутое дельтой из r1: golden/скриншот-покрытие Room/General как отдельную тему,
implementation-детали центрирования шарика тумблера, полный текст
docs/USER-GUIDE.md(EN). - Не проверял, как именно реализация проведёт toggle-рендер через
placement === 'additional'для случая «уже сохранён» (правкиmanualEntry/условий вradar-section.ts) — это код-ревью после реализации; на этапе ТЗ проверено, что наблюдаемый результат сформулирован однозначно и проверяем (AC11–AC13 + новое предложение §6.6), реализация вольна выбирать конкретные условия. - Автотесты и гейты
typecheck/test/build/golden:verifyне запускались — кода по issue #602 нет (git branch -a | grep -i 602пуст), предмет ревью — исключительно текст ТЗ; они относятся к код-ревью (§2.7) после реализации.
Вердикт
Обе находки предыдущего раунда закрыты по существу и проверяемо: Medium — продуктовым решением с прямой ссылкой на используемое условие кода и явным отказом от нового поля данных (не конфликтует с §5); Low — точным исправлением пары файлов changelog. Дельта не вносит новых High или Medium находок и не разрушает ни один вывод r1: наследуемые разделы не затронуты, а точки соприкосновения с дельтой (§6.6, AC11–AC13, §10/§16) перепроверены заново и непротиворечивы. ТЗ готово к разработке.
Вердикт: зелёный · заход r2 · блокирующих циклов 1/4 · High: 0 · Medium: 0
Материал раунда
- Ветка:
dev, рабочая копия ревью — детачед HEAD наa4667562470dee913dfdc14b57adb7644eeafa07(коммит публикацииSPEC-REVIEW-602-r1.md); кода по issue #602 между r1 и r2 не появлялось (git branch -a | grep -i 602— пусто). - Тело issue снято
gh issue view 602 --repo Matysh/houseplan-card --json body2026-09-20, 188 строк — предмет этого раунда; sha256 нормализованного тела для официального якоря пишет конвейер публикации, как и в r1 (issue #414); для справки sha256 сырого текста, полученногоgh issue view --json body -q .body:c861f9a9fbecbefdec69d3d5dbb3951edc40266586e039bde3efa3f9ceb2490e. - Комментарии issue на момент ревью: 5 (
gh issue view 602 --json comments→ 5 элементов) — аналитика, вопросы владельцу, решения владельца, вердикт конвейера r1, ответ автора на r1.
Материал раунда
- Ветка:
dev, коммитa4667562470d— ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Дерево материала:
f4e7de452fa2f8e4738f9bd9d22c9d6fb642a8a2git log --all --format='%H %T' | grep f4e7de452fa2 - Тело issue:
8f8081ec29db1c104189682530643bde421d91127170b2c635107c595950a5a9 - Вердикт конвейера:
green· High 0