Files
houseplan-card/docs/reviews/SPEC-REVIEW-660-r3.md
T
2026-09-26 07:43:22 +00:00

226 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-660-r3
- **Issue:** https://github.com/Matysh/houseplan-card/issues/660
- **Этап:** `S4-spec-review` (ревью ТЗ, PROCESS.md §2.4)
- **Трек:** полный (не пересматривался в r3, обоснование не менялось — см. «Унаследовано
из r2»)
- **Материал:** тело issue #660 в редакции r3 (`updatedAt: 2026-09-26T07:37:01Z`);
комментарий автора «ТЗ обновлено до r3 по SPEC-REVIEW-660-r2» (`2026-09-26T07:36:59Z`)
предшествует установке `S4-spec-review` (07:37:01) на 2 секунды — тот же паттерн,
что в r1→r2. Таймлайн меток: вердикт r2 (07:34:32) → `S4-spec-review` снята,
`S3-spec` выставлена (07:35:09) → комментарий автора о доработке (07:36:59) →
`S3-spec` снята, `S4-spec-review` выставлена (07:37:01). Тело сверено напрямую с
`docs/reviews/SPEC-REVIEW-660-r2.md`: раздел `## ТЗ` в r2 уже был полным; в r3
изменены только Скоуп п.3, Не-скоуп (одна фраза), AC4, AC9 и вводная строка
«Редакция r3» — остальной текст (Сценарий, До/После, Проблема по коду, AC1/AC2/
AC3/AC5…AC8/AC10, UX/i18n/данные, таблица «AC · чем доказан · чем краснеет», План
автотестов, Риски, Откат, Release-артефакты, «Принято предположительно») не
редактировался.
- **Заход:** r3 · блокирующих циклов израсходовано 2 из 4 (полный трек, лимит 4)
- **Роль:** ревьюер ТЗ (не автор)
## Скоуп ревью
Задача не изменилась с r1/r2: полировка шапки главной панели после #647 — (1)
inline-кнопки сводной панели остаются активными во всех трёх редакторах на ширинах
>480 px; (2) расстояние между блоком редакторов и блоком зума уменьшается вдвое до
измеримых значений; (3) резерв под крестик закрытия переезжает внутрь `.modes`,
включая явную оговорку поведения на ≤480 px; (4) `Esc` получает единый терминальный
выход в View из Plan и Devices.
Проверялось: закрыт ли единственный High SPEC-REVIEW-660-r2 (крестик пропадал на
≤480 px вместе со всем `.modes`, AC9 был недоказуем, единственный touch-выход из
Plan/Devices исчезал); не появилось ли новое противоречие в изменённых Скоуп п.3 /
Не-скоуп / AC4 / AC9; согласие обновлённого текста с кодом «как есть» и с
`docs/UX-MODES.md` (в частности со строками 17-20 про «editor X slot» телефонной
шапки, которые в r2 не были предметом находки).
**Дельта локальна.** В отличие от r1→r2 (где дописывался весь раздел `## ТЗ`
впервые, то есть объём дельты был сопоставим с задачей), r2→r3 меняет пять коротких
фрагментов текста, все они — прямой ответ на единственную находку High-1 r2. Раздел
разбирается по дельте (PROCESS.md §2.10): полностью проверены только Скоуп п.3,
Не-скоуп, AC4, AC9 и их взаимная непротиворечивость с кодом/каноном; остальные
части ТЗ, не тронутые дельтой (AC1, AC2, AC3, AC5-AC8, AC10, План автотестов,
Риски, Откат, Release-артефакты, «Принято предположительно», выбор трека,
правомерность Q1/Q2), приняты без повторного разбора — см. «Унаследовано из r2».
## Как проверялось
1. Прочитаны `docs/process/REVIEWER.md` целиком и PROCESS.md §2.4, §2.5, §2.10, §4,
§7.1, §7.2 (по ссылкам конспекта).
2. Прочитано текущее тело issue #660 целиком (`gh issue view 660 --json body`) и
комментарии (`gh issue view 660 --json comments`): «Аналитика», ответ владельца
Q1/Q2, вердикты r1/r2, комментарий автора «ТЗ обновлено до r3».
3. Сверена история меток issue (`gh api .../timeline --paginate`) — порядок событий
red-вердикт r2 → `S3-spec` → комментарий автора → `S4-spec-review` подтверждён
(см. «Материал» выше).
4. Прочитаны `docs/reviews/SPEC-REVIEW-660-r1.md` и `-r2.md` целиком; единственная
находка r2 (High-1: перенос крестика внутрь `.modes` без оговорки по ширине
ломает видимость на ≤480 px) сверена построчно с новым текстом (раздел
«Закрытие раунда r2» ниже).
5. Прочитан `docs/UX-MODES.md:1-40` (описание телефонной шапки, включая «the editor
X slot of #647» как отдельный от вкладок режимов элемент) и строки 56-61,
116-125 (обе цитаты, которые AC10 требует заменить) — новый текст Скоуп п.3/AC4
им не противоречит: канон уже описывал крестик на телефоне как элемент,
присутствующий независимо от режима, что и воспроизводит r3.
6. Перечитан код, который правит дельта:
- `src/styles/chrome.styles.ts:150-166` — медиазапрос `max-width: 480px`:
список `display: none` (`.title, .modes, .spacer, .header-action,
.summary-control`) и отдельное правило `.head > .zoomctl, .head >
.editor-close-slot { flex: none }`; подтверждает, что сегодня `.modes`
прячется целиком, а `.editor-close-slot` — нет (независимое от него правило);
- `src/houseplan-card.ts:10805-10824` — текущая разметка: `.modes` (только при
`_canEdit`) и `<span class="editor-close-slot">` как физический sibling после
`.modes`, перед `<span class="spacer">`;
- `docs/USER-GUIDE.ru.md:265-278` («Шапка на телефоне») — «В редакторе крестик
закрытия остаётся в строке» — подтверждает наблюдаемое сегодня поведение,
которое AC9/Скоуп п.3 r3 обязаны сохранить после переноса слота в `.modes`.
7. Проверено, что продуктового кода для #660 в `origin/dev...HEAD` по-прежнему нет
(`git diff origin/dev...HEAD --stat` пуст, `git log --oneline -5` показывает
только доковые коммиты предыдущих ревью) — гейты не гоняются, этап `spec`.
## Находки
Не найдено. Единственная находка SPEC-REVIEW-660-r2 закрыта содержательно (см.
«Закрытие раунда r2»), новых High/Medium/Low в изменённых фрагментах не появилось.
## Что проверено и корректно
- **High-1 из r2 закрыт содержательно и правильным из двух предложенных путей.**
r2 предлагал на выбор: (а) крестик остаётся физическим соседом `.modes` на
≤480 px, либо (б) медиазапрос телефонной шапки переписывается так, чтобы прятать
только `.modetab`-кнопки, сохраняя видимость и позицию крестика. Автор выбрал
(б): Скоуп п.3 теперь явно говорит «На ≤480 px не скрывать весь `.modes`:
скрывать только `.modetab`, а контейнер делать визуально прозрачным и
схлопнутым до 24 px слота» — техническое решение согласуется с существующим CSS
(`.modes` сегодня — `display: inline-flex; gap; background; border-radius;
padding` — все эти свойства перечислены как то, что нужно снять на ≤480 px,
не голословно).
- **AC4 и AC9 обновлены синхронно со Скоуп п.3, а не только он.** AC4 явно
добавляет: «На ≤480 px `.modetab` скрыты, но `.modes` и его слот остаются; в
редакторе виден и работает крестик, в View остаётся неинтерактивный пустой
резерв» — это ровно то, что делает AC9 доказуемым (r2 констатировал: «AC9
недоказуем как написан» именно потому, что слот тогда пропадал целиком). AC9
теперь прямо называет фактическую защиту: «на 390/480 px крестик остаётся
видимым в строке и touch-кликом закрывает Plan, Devices и Decor; это
обязательный путь выхода при скрытых `.modetab` и отсутствии пункта View в
gear-меню» — устраняет второй пункт находки r2 (тупик для touch-only
администратора).
- **Не-скоуп больше не противоречит Скоуп п.3.** r2 отмечал: «восстановление
видимости крестика на ≤480 px требует трогать CSS-структуру телефонной шапки...
а это прямо соседствует с исключённой поверхностью и нигде не выделено как
разрешённое исключение». В r3 добавлена явная оговорка: «Адаптивное правило
самой шапки для сохранения крестика на ≤480 px входит в скоуп» — снимает
формальное противоречие между «Не-скоуп: изменение мобильного gear-меню» и
фактически требуемой правкой CSS-медиазапроса шапки (это разные поверхности:
меню шестерёнки не трогается, трогается только `.modes`/`.editor-close-slot`).
- **Новый текст согласован с каноном, а не только с самим собой.**
`docs/UX-MODES.md:17-20` уже описывает крестик как элемент телефонной шапки,
присутствующий независимо от режима («... the zoom cluster, one gear and — for
an admin — the editor X slot of #647»); r3 воспроизводит именно эту семантику
(«слот остаётся» в View как пустой резерв, в редакторе — как активная кнопка),
а не вводит новое расхождение. AC10 по-прежнему называет ровно две цитаты канона
на замену (строки 56-61 «outside the editors», 116-125 «disappear in Plan,
Devices and Background») — обе останутся неверны после реализации и обе учтены.
- **Мутация для AC4 прямо кодирует закрытую находку.** Таблица «AC · чем доказан ·
чем краснеет» для AC4: «мутант возвращает слот sibling либо скрывает весь
`.modes` на ≤480 px» — это буквально откат к архитектуре, которую нашёл High-1
r2; мутант не абстрактный, а прицельно бьёт по регрессии, которую разбирало
предыдущее ревью.
- **Единственный технический вопрос, который мог бы остаться открытым
(визуальная позиция крестика на ≤480 px «как до #660», не только видимость и
кликабельность) — закрыт через «Принято предположительно».** Раздел явно
называет: «На ≤480 px сохранить контейнер в layout, скрыть только `.modetab` и
убрать у схлопнутой группы фон/padding, чтобы видимым остался прежний 24 px
крестик/резерв» — это техническая деталь компоновки (снятие padding/background
у пустого контейнера), а не продуктовое решение, поэтому её место — именно в
«Принято предположительно», не в отдельном AC; помечена как «поменять
свободно», как и требует §7.1.
- Остальной текст ТЗ (не тронутый дельтой r3) не проверялся заново в этом
раунде — см. «Унаследовано из r2».
## Чего не проверял
- Гейты (`tsc`, `npm test`, `npm run build`, `check-docs.mjs`, смоки, golden,
инварианты) — не прогонял: этап `spec`, продуктового кода для #660 в
`origin/dev...HEAD` по-прежнему нет (`git diff` пуст). Предмет код-ревью после
реализации.
- Не проверял заново AC1, AC2, AC3, AC5-AC8, AC10, План автотестов, Риски, Откат,
Release-артефакты, «Принято предположительно» (кроме пункта про ≤480 px,
разобранного выше) — эти части не менялись между r2 и r3, дельта их не задевает
(см. «Унаследовано из r2»).
- Не измерял в браузере фактическую видимую позицию крестика на 390/480 px после
снятия padding у `.modes` — реализации ещё нет; это станет предметом код-ревью
и browser-смока (`smoke_mobile_view_header.mjs`), когда появится код.
- Не проверял, действительно ли `scripts/mutation-registry.mjs` уже содержит
указанные в таблице мутанты — план автотестов только обещает их добавить, что
нормально для стадии `spec`.
- Не пересматривал выбор полного трека и правомерность вопросов Q1/Q2 — оба
установлены в r1 и не пересматривались в r2; текст, на котором они основаны, не
редактировался и в r3.
## Закрытие раунда r2
| Находка (r2) | Чем закрыта | Где это видно |
|---|---|---|
| High-1: Скоуп п.3 переносит крестик внутрь `.modes` без оговорки по ширине; `.modes` скрыт `display:none` на ≤480 px → крестик пропадает из телефонной шапки, AC9 недоказуем, touch-only администратор теряет единственный способ выйти из Plan/Devices | Скоуп п.3 добавляет явную оговорку: на ≤480 px скрывается только `.modetab`, `.modes`-контейнер остаётся в layout визуально прозрачным и схлопнутым до 24 px слота; AC4 и AC9 переписаны синхронно (крестик/слот остаются, обязательный touch-выход назван прямо); Не-скоуп явно вносит адаптивное правило шапки как разрешённое исключение | тело issue #660, разделы «Скоуп» п.3 (последние два предложения), «Не-скоуп» (последнее предложение первого пункта), «AC4», «AC9» |
Находка закрыта содержательно, выбранным путём (б) из двух предложенных в
SPEC-REVIEW-660-r2 «Как закрыть», без формальной отписки: изменения синхронны
между Скоуп/Не-скоуп/AC4/AC9, а не точечная правка одной строки.
## Унаследовано из r2 (без повторной проверки в этом раунде)
- **Полнота обязательных разделов §7.1 и структура ТЗ по образцу #647** —
установлена в SPEC-REVIEW-660-r2 (закрытие High-1 r1); текст этих разделов
(Сценарий, До/После, Проблема по коду, UX/i18n/данные, таблица «AC · чем
доказан · чем краснеет» кроме строки AC4, План автотестов, Риски, Откат,
Release-артефакты, «Принято предположительно» кроме пункта про ≤480 px) не
редактировался между r2 и r3.
- **Соответствие AC10/Release-артефактов канону `docs/UX-MODES.md`** —
установлено в SPEC-REVIEW-660-r2 (закрытие High-2 r1); текст AC10 не менялся.
- **Измеримые цели AC3 (50±1 px / 40.5±1 px)** — установлены в
SPEC-REVIEW-660-r2 (закрытие Medium-1 r1); текст AC3 не менялся.
- **Архитектурная состоятельность AC1/AC2** (снятие guard в `renderControls()`
без новой width-detection логики) и **реализуемость AC7/AC8** (терминальный
`Esc` укладывается в существующую структуру `_onKey`) — проверены по коду в
SPEC-REVIEW-660-r2, текст этих AC не менялся.
- **Отказ от лёгкого трека (`small`) и выбор полного трека** — обоснование не
менялось с r1 (несколько поверхностей + новый UX-контракт), не пересматривался
в r2 и r3.
- **Продуктовая правомерность вопросов Q1/Q2** — установлена в r1, не
пересматривалась в r2 и r3.
## Вердикт
Единственная находка SPEC-REVIEW-660-r2 (High-1: перенос крестика внутрь `.modes`
без оговорки по ширине ломал видимость на ≤480 px) закрыта содержательно и
синхронно во всех местах текста, которые она затрагивала: Скоуп п.3, Не-скоуп,
AC4, AC9. Выбранное решение — переписать медиазапрос телефонной шапки так, чтобы
прятать только кнопки режимов, а не весь `.modes` — согласуется с действующим
кодом (`chrome.styles.ts:150-166`) и с каноном `docs/UX-MODES.md:17-20`, который
уже описывает крестик как элемент телефонной шапки, не зависящий от видимости
вкладок режимов. Новых High/Medium в изменённых фрагментах не найдено; остальной,
не тронутый дельтой текст, был полностью проверен в r2 и не пересматривался.
Продуктового кода для задачи всё ещё нет, гейты не применимы к стадии `spec`.
Зелёный вердикт: ТЗ готово к разработке, находок нет.
Вердикт: зелёный · заход r3 · блокирующих циклов 2/4 · High: 0 · Medium: 0 → в задаче
---
---
<!-- material-anchors: сгенерировано конвейером (#414) -->
## Материал раунда
- Ветка: `dev`, коммит `d65b9e39d5e6` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
- Дерево материала: `d55b5f3d47e446be687eda886e90efad6d0bccb3`
```
git log --all --format='%H %T' | grep d55b5f3d47e4
```
- Тело issue: `8934e3862ceec6de29d1fd24fe32df49790efd62d8288fb28e36eecb05e44387`
- Вердикт конвейера: `green` · High 0