mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
226 lines
22 KiB
Markdown
226 lines
22 KiB
Markdown
# 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
|