docs: review document for #372

Issue: #372
User-Visible: no
This commit is contained in:
claude[bot]
2026-08-29 13:16:04 +03:00
committed by Sergey Matyunin
parent d696541aba
commit 6392179013
+190
View File
@@ -0,0 +1,190 @@
# SPEC-REVIEW-372-r1
Issue: [#372](https://github.com/Matysh/houseplan-card/issues/372) — «Remove empty
header spacing when `title` is empty in `houseplan-space-card`»
Этап: spec (PROCESS.md §2.4) · заход r1 · блокирующих циклов израсходовано 0 из 4
ТЗ: `docs/specs/372-space-card-empty-title.md`, коммит `edb9b6b3` (ветка
`issue/372-space-card-empty-title`)
Трек: полный (аналитика назвала критерий `small`, который задача не проходит —
новый UX-контракт для `title`)
## Скоуп ревью
Первый заход по этой задаче — предыдущего вердикта нет, разбор полный.
Проверялось: соответствие `docs/SCOPE.md`, обязательные разделы ТЗ по §7.1,
однозначность и доказуемость каждого AC, отсутствие догадок, выданных за факт,
корректность продуктового вопроса и решения владельца, трейлеры коммита.
## Как проверялось
1. Прочитаны `docs/SCOPE.md`, `AGENTS.md`, `PROCESS.md` (§2, §3, §4, §7, §8, §12).
2. Прочитано тело issue #372 и все 4 комментария: аналитика → продуктовый вопрос
Q1 → решение владельца (Default) → публикация ТЗ.
3. Прочитан `docs/USER-GUIDE.ru.md` §18 (`houseplan-space-card`) — терминология
`title`/`show_button`/`button_target` в ТЗ совпадает с действующим гайдом.
4. Прочитан `docs/CANVAS.md` §4, §4.1, §6 — канонический документ подсистемы,
так как задача трогает `spaceFrame`/`contentFrame`, разделяемые с иконочным
масштабированием.
5. Каждое фактическое утверждение ТЗ сверено с текущим кодом на `dev`-состоянии
рабочей копии (сам ТЗ-коммит кода не трогает):
- `src/space-card.ts:812,827` — `title = config.title !== undefined ? config.title : sp?.title || ''`;
`.hp-static-title` рендерится только если `title` truthy → подтверждён факт
«явная пустая строка уже не создаёт header».
- `src/space-geometry.ts:419-429` (`spaceFrame`) — симметричный `pad = 0.05`
на всех четырёх сторонах; fallback на `space.vb` без паддинга либо на
legacy unit square — подтверждён факт «полоса — верхняя часть 5%-го поля»
и корректность контракта п.6 («если content frame отсутствует, compact
mode не выдумывает новый crop»).
- `src/space-render.ts:274-275,543` — `vb = [fr.x, fr.y, fr.w, fr.h]` идёт
прямо в `viewBox`; `space-render.ts` импортируется только из
`space-card.ts` → подтверждена локальность правки (не задета полная
`houseplan-card`).
- `src/houseplan-card.ts:5516-5517` — тот же `spaceFrame` вызывается без
переопределения pad → допустимость «необязательного параметра» в ТЗ
(раздел «Принято предположительно») не меняет дефолтный путь других
потребителей.
- `src/space-geometry.ts:457-499` (`iconUnit`, `iconCqw`) — масштаб иконок
считается от `contentFrame(items, {pad:0})` и делится на `vb[2]` (ширину),
а не высоту. Контракт ТЗ (п.4: «меняются только `viewBox.y` и `height`,
ширина неизменна») технически не задевает формулу размера иконок и
`declump`-раскладку — риск «иконки поедут» в ТЗ закрыт корректно.
- `src/space-render.ts:541` — `style="aspect-ratio:${vb[2]}/${vb[3]}..."` —
подтверждает, что уменьшение `height` уменьшит и высоту сцены/карточки, как
заявлено в «Что человек увидит».
- `demo/docs/` не содержит упоминаний `space-card` → подтверждена гипотеза
ТЗ «канонические PNG документации не содержат static space card, поэтому
`check-docs` не даст визуальной регрессии по этой карточке».
- `docs/specs/README.md` diff — строка добавлена корректно, ссылка и путь
совпадают.
6. Файлы, названные в разделе «Затронутые файлы», существуют:
`demo/smoke_space_card.mjs`, `test/space-geometry.test.mjs`.
7. Коммит `edb9b6b3` проверен `git show -s --format=full`: трейлеры
`Issue: #372` / `User-Visible: no` корректны для документации без изменения
поведения (класс C, PROCESS.md §1/AGENTS.md).
Гейты кода не гонялись — на этапе spec-ревью нет диффа продуктового кода;
единственный диф — `docs/specs/**` и `docs/specs/README.md`, класс C.
## Проверка по SCOPE.md
Сценарий закрывает J1 (`docs/SCOPE.md`: «Show the whole home... live spatial
overview») в его компактном read-only варианте — `houseplan-space-card` явно
описана в SCOPE.md как View-поверхность. Изменение чисто визуальное, не
расширяет интерактивность, не затрагивает лок-инвариант, не входит в
Out-of-scope список. Соответствует.
## Проверка обязательных разделов (§7.1)
Присутствуют все обязательные разделы: сценарий · что человек увидит до/после ·
проблема · скоуп и не-скоуп · контракт поведения (9 пунктов) · UX и
доступность · модель данных/миграция/совместимость · i18n · AC1–AC8 с
доказательством · план автотестов (7 шагов) · риски (привязаны к AC) · откат ·
release-артефакты. Дефектов нет.
Первые два раздела («Сценарий», «Что человек увидит») отвечают на требуемые
вопросы: персона, поверхность, момент; и «одной фразой, без терминов
реализации» — выполнено, реализационные детали (`spaceFrame`, `viewBox`)
вынесены в раздел «Проблема», как и предписано структурой.
## Проверка AC
Все 8 AC пронумерованы, каждый называет способ доказательства (`unit`,
browser `smoke`, «ревью кода», CI). Формулировки однозначны и допускают
проверку числом (координаты `viewBox`, `getBoundingClientRect()`), а не
описательно. AC5 отдельно защищает вырожденные/fallback случаи от NaN/
Infinity — соответствует существующему коду (`spaceGeometry.ts` уже обрабатывает
`DEGENERATE`/`SANE_LIMIT`, ТЗ не выдумывает новый механизм, а требует его
сохранения).
Замечаний по AC нет.
## Проверка на догадки, выданные за факт
Раздел «Проблема» содержит числовые утверждения (`topGap = 0 px` при пустом
title, `topGap = 37 px` при непустом) — они взяты из аналитического
комментария к issue («Проверенный факт»), а не из самого ТЗ, и подтверждаются
кодом (см. «Как проверялось», п.5). Формулировки контракта поведения — не
предположения, а прямое отражение того, что уже верно для существующего кода
(`spaceFrame`, `iconCqw`) плюс явное решение владельца по Q1.
Раздел «Принято предположительно, поменять свободно» корректно ограничен
непродуктовыми деталями (имя helper, точное место арифметики, конкретная
fixture, способ переиспользования `spaceFrame`) — эти решения не наблюдаемы
пользователем и по §7.1 их не нужно выносить владельцу.
Единственная пограничная зона — поведение `title` с одними пробелами
(whitespace-only). ТЗ явно относит её к «Не-скоуп» («значение, отличное от
точной пустой строки, сохраняет текущую семантику») и не нормализует. Это
можно было бы счесть продуктовым пограничным случаем (§7.1 перечисляет
«поведение в пограничном случае» как повод спросить владельца), но исходный
текст issue и Q1 говорят именно о `title: ""`, альтернативное поведение не
запрошено пользователем, а решение сохраняет статус-кво (наименьшее
удивление) и явно задокументировано, а не скрыто. Не считаю это находкой —
уровень Low, снимаю с записью: граница названа, обоснована и не меняет
видимое поведение относительно текущего `dev`.
## Проверка вопроса владельцу и его решения
Q1 задан корректно по форме §7.1: что неясно · что изменится от ответа ·
предлагаемый вариант по умолчанию (Default/Альтернатива). Вопрос продуктовый
(влияет на видимый контракт `title`), не технический. Issue корректно ушёл в
`S3-spec` + `blocked` на время ожидания и разблокирован после ответа владельца.
ТЗ включает принятое решение (Default) без искажений.
## Проверка трейлеров и артефактов
- `Issue: #372` / `User-Visible: no` на коммите `edb9b6b3` — корректно, диф не
меняет пользовательское поведение (только `docs/specs/**`).
- `docs/specs/README.md` — запись добавлена, путь и заголовок совпадают.
- Ссылка issue ↔ ТЗ на месте с обеих сторон (тело issue ссылается на файл ТЗ в
ветке; файл ТЗ ссылается на issue).
## Находки
Нет находок уровня High или Medium. Одна Low-находка (whitespace-only title,
см. выше) рассмотрена и снята с записью прямо в этом документе — правка ТЗ не
требуется.
## Что проверено и корректно
- Полнота обязательных разделов ТЗ (§7.1).
- Однозначность и доказуемость всех 8 AC.
- Фактические утверждения о текущем поведении (`topGap`, `pad=0.05`,
использование `spaceFrame`/`iconCqw`) — подтверждены чтением
`src/space-card.ts`, `src/space-geometry.ts`, `src/space-render.ts`,
`src/houseplan-card.ts`.
- Локальность правки: `space-render.ts` используется только `space-card.ts`;
`spaceFrame` также используется в `houseplan-card.ts` без переопределения
`pad`, поэтому необязательный параметр не сломает дефолтный путь полной
карточки — заявленный в ТЗ риск «случайно меняется полная карточка»
технически обоснованно закрывается выбранным подходом.
- Независимость масштаба иконок (`iconUnit`/`iconCqw`) от высоты
`viewBox` — компакт-режим меняет только `y`/`height`, что не пересекается с
формулой размера иконок (делится на ширину `vb[2]`, не на высоту).
- Отсутствие static space card в канонических docs-скриншотах — заявление ТЗ
о нулевом визуальном дифе `check-docs` подтверждено по дереву `demo/docs/`.
- Продуктовый вопрос Q1 задан и решён по процессу, решение отражено в ТЗ без
искажений.
- Трейлеры коммита `edb9b6b3` и запись в `docs/specs/README.md`.
- Названные файлы для тестов (`demo/smoke_space_card.mjs`,
`test/space-geometry.test.mjs`) существуют.
## Чего не проверял
- Продуктовый код не написан на этом этапе — код-ревью впереди, при переходе в
`S6`→`S7`. Технической реализуемости контракта я касался только для того,
чтобы убедиться, что ТЗ не строится на неверных фактах о коде (не для
оценки будущей реализации).
- Гейты `typecheck`/`test`/`build`/`golden`/`check-docs`/смоки не гонялись —
на spec-ревью нет диффа `src/**`, единственный диф — `docs/specs/**`.
- Не проверял историю других issue (#150, #214 и т.д.), кроме тех, что нужны
для контекста самого процесса ревью (эта задача — r1, «Унаследовано» не
применимо).
## Вердикт
Зелёный. ТЗ полное, каждый AC доказуем и однозначен, факты о текущем
поведении подтверждены чтением кода, продуктовый вопрос корректно решён
владельцем до написания ТЗ, догадок за фактами не найдено. Единственная
пограничная зона (whitespace-only title) рассмотрена и снята Low-находкой без
правки ТЗ.