Files
houseplan-card/docs/reviews/SPEC-REVIEW-211-r1.md
T
2026-08-19 21:20:16 +00:00

227 lines
19 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.
# Ревью ТЗ — issue #211, цикл r1
- **Issue:** https://github.com/Matysh/houseplan-card/issues/211
- **ТЗ:** `docs/specs/211-device-icons-visual-parity.md` (коммит `93200eb`, ветка
`issue/211-device-icons-visual-parity`)
- **Трек:** обычный (аналитика явно исключила `small`/`trivial`)
- **Вердикт:** жёлтый · цикл r1/4 · High: 0 · Medium: 1 (в скоупе задачи) · Low: 2
## Скоуп ревью
Проверялось только ТЗ как артефакт этапа `S4-spec-review`: обязательные разделы
§7.1 PROCESS.md, однозначность и доказуемость AC1…AC10, соответствие
`docs/SCOPE.md` (J1/J2), `docs/USER-GUIDE.ru.md`, `docs/TOUCH-SUPPORT.md`, и
отдельно — фактическое соответствие числовых утверждений ТЗ нормативному
источнику: тому же архиву дизайнера, что и в #179, плюс текущей реализации в
`src/styles.ts` (описанной как «до»). Продуктовый код по #211 не существует
(issue не дошёл до `S5-ready`, диапазон `origin/dev..HEAD` содержит только
`docs/specs/211-*.md` и правку `docs/specs/README.md`), поэтому код не
проверялся и гейты §8 PROCESS.md к этому циклу неприменимы.
## Как проверялось
1. Прочитаны `docs/SCOPE.md`, `AGENTS.md`, `PROCESS.md` целиком.
2. Прочитано тело issue #211 и оба комментария (аналитика + «ТЗ готово»), а
также issue #179 целиком — тело и все 15 комментариев обоих циклов ревью
ТЗ и код-ревью, чтобы знать, какие решения владельца уже приняты и что
именно было принято/исправлено там (`M1–M5`, `L1–L2` в
`SPEC-REVIEW-179-r1.md`/`r2.md`).
3. Прочитан файл ТЗ `211-device-icons-visual-parity.md` целиком (354 строки) и
`docs/specs/179-device-icons-redesign.md` целиком — как источник приоритета
№4 по собственной цепочке разрешения расхождений ТЗ #211.
4. **Архив дизайнера скачан заново и распакован** (`curl` по той же ссылке из
тела issue #179, `sha256sum` совпал с указанным в ТЗ #211
`63670C73E25D1E59DDAF1BE236F3D7F2FAC827B9B5D6DD4B77125EA9BC012025`) —
независимая проверка, не пересказ ТЗ #179:
- подтверждена геометрия shell/core (`<path>`/`<rect>` в `Light/Dark Icon
Default*.svg`: shell — круг диаметром `101.5`, core — `<rect rx="40">`
`80×80`, отношение `1.26875`);
- подтверждён pill value-badge (`Double Default Right.svg`: `Frame_2` —
путь `y: 24…87`, высота `63 = 0.7875×80`, радиус скруглений `31.5 =
0.39375×80`, то есть ровно половина высоты);
- подтверждены цвета состояний построчным `grep` по `fill`/`stroke` в
`Icon Hover/Active/Alert Value/Selected/Focus Visible/Lock/Unlock.svg`
для обеих тем;
- подтверждён `stroke="#252525" stroke-opacity="0.75"` в
`Dark/Icon Default No Blur.svg` (Dark shell default) и `stroke-dasharray
"6 6"` в `Virtual Device *.svg` (Virtual shell);
- подтверждена сама регрессия, зафиксированная в Dark/Unlock.svg архива
(`fill="#1DC21D"`, зелёный) — и то, что ТЗ №211 корректно, вслед за ТЗ
#179, отвергает этот файл в пользу решения владельца («Unlock — янтарный
в обеих темах»), а не проецирует его буквально;
- измерена реальная bounding box глифа (`svgpathtools`, путь `id="Vector"`)
в `Icon Default/Hover/Active/Default No Blur.svg` (общий «колокольчик»)
и в `Lock.svg`/`Unlock.svg` — см. M1 ниже;
- проверено существование каждого документа, который ТЗ №211 §4 называет
нормативным источником (`SPECIFICATION.md`, `DEVELOPER_HANDOFF.md`,
`ACTIVE_ANIMATION_SPEC.md`, `COMPARISON_NOTES.md`) — см. L1.
5. Сверено с текущей реализацией `src/styles.ts` (строки 1860–2214): каждое из
шести «подтверждённых расхождений» ТЗ §3 сопоставлено построчно с кодом —
`border-radius: 28%` (:1961), `--mdc-icon-size: … * 0.62` (:1984),
value-section `border-radius: … * 0.18` при высоте `.7875` (:2180,:2188),
безусловный `border: 1px solid #BCBCBC` без тёмного варианта (:1912).
6. Прочитаны релевантные фрагменты `docs/USER-GUIDE.ru.md` (термин «маркер»,
отсутствие конфликтующей терминологии) и целиком `docs/TOUCH-SUPPORT.md`
(«Documentation rule», канонические теги `Touch editor: …`).
7. Код не запускался, гейты не прогонялись — на этапе ревью ТЗ кода нет.
## Находки
### M1 — целевое соотношение «MDI viewport = 0.5 × core» не подтверждено ни одним источником архива и расходится с прямым измерением SVG
**Файл:** `docs/specs/211-device-icons-visual-parity.md:44-45` (§3, п.2),
`:123` (§7.1, таблица), AC1 (`:241-244`)
ТЗ утверждает как факт: «пакет использует `40 × 40` внутри core `80 × 80`, то
есть `0.5 × core`» и заносит `MDI viewport | width = height = 0.5` в таблицу
геометрического контракта §7.1 с допуском **не более 0,5 CSS px** на 32/56/96
px (тот же допуск, что и для проверенно точных чисел вроде `1.26875` и
`0.7875`). Это число прямо используется в AC1 как критерий приёмки.
Проверка источников:
- `SPECIFICATION.md`, `DEVELOPER_HANDOFF.md`, `ACTIVE_ANIMATION_SPEC.md`,
`PACKAGE_ANNOTATION.txt` — ни один не называет размер/долю icon-viewport
внутри core; `SPECIFICATION.md` §8 говорит только о shell/core/border/shadow.
- Прямое измерение bounding box самого глифа (`svgpathtools`, путь
`id="Vector"`) в реальных SVG даёт **не 0.5**: `Icon
Default/Hover/Active/Default No Blur.svg` (общий глиф-колокольчик) —
`33.33 × 33.33` = `0.417 × core`; `Lock.svg`/`Unlock.svg` —
`26.67 × 35.0` = `0.333–0.4375 × core`.
- Единственное место архива, где встречается ровно `50%`, — файл
`Index.html` (`.new .glyph { width: 50%; height: 50%; }`), интерактивный
demo-компаратор «старый/новый» дизайн. Но: (а) он не входит в список
источников §4 ТЗ (там перечислены только owner-решения, три `.md`-документа,
«SVG архива» и ТЗ #179 — без `Index.html`); (б) сам этот демо-файл
использует приближённые круглые px-значения (`--core-size: 42px` при
`--s: 56px`, то есть core/marker `≈0.75`, тогда как в реальных экспортных
SVG это отношение `0.7882` — расхождение ~5%), то есть он иллюстративный
прототип, а не пиксель-точная копия экспортных assets.
Итог: `0.5` — правдоподобное **производное** значение (bbox глифа + типичный
внутренний padding самих MDI-иконок ≈10–15% могли бы дать assigned-frame
≈39–41), но ТЗ подаёт его как прямую цитату архива наравне с числами, которые
я независимо проверил и подтвердил буквально (`1.26875`, `0.7875`,
`0.39375`, все цвета состояний). Ни один текстовый документ этого числа не
называет, а единственный SVG-источник с буквальным `50%` не упомянут в §4 и
сам не является пиксель-точным.
**Почему это важно:** AC1 — единственный количественный критерий именно для
формы/масштаба глифа, то есть сердцевина задачи «маркер визуально совпадает с
пакетом». Раздел §11 требует построить независимую таблицу «Reference SVG ↔
Runtime» именно для того, чтобы новый golden не мог сам стать себе эталоном
(это и есть причина, по которой заведён #211). Если строка «Reference SVG»
для glyph viewport унаследует непроверенное число `0.5`, фикстура будет
защищать неверную/неподтверждённую цель с той же уверенностью, что и
корректные строки — то есть повторит тот самый механизм регрессии, из-за
которого возник этот баг.
**Требуется** одно из:
1. явно сослаться на `Index.html` как источник и показать расчёт (bbox +
допущение о внутреннем padding MDI) в §4/§7.1, чтобы ревьюер кода видел
основание числа, а не готовый вывод; либо
2. перенести именно эту строку в §16 «Принятые технические предположения» —
как единственную геометрическую величину, не имеющую прямого текстового
или однозначного SVG-подтверждения, — и явно разрешить реализации/ревью
скорректировать её при визуальном сравнении с реальным MDI-глифом (в
отличие от статичного примера-«колокольчика» из пакета).
Находка в скоупе задачи (это её собственный AC1); блокирующей не является —
одна Medium без High даёт жёлтый вердикт и правку в этом же ТЗ.
### L1 — §4 называет нормативным источником несуществующий файл `COMPARISON_NOTES.md`
**Файл:** `docs/specs/211-device-icons-visual-parity.md:62-63`
Порядок приоритета источников перечисляет «`SPECIFICATION.md`,
`DEVELOPER_HANDOFF.md`, `ACTIVE_ANIMATION_SPEC.md` и `COMPARISON_NOTES.md`
архива #179». В реально скачанном и распакованном архиве (тот же SHA-256,
что и в ТЗ) присутствуют `README.md`, `SPECIFICATION.md`,
`DEVELOPER_HANDOFF.md`, `ACTIVE_ANIMATION_SPEC.md`, `PACKAGE_ANNOTATION.txt`,
`manifest.json`, `Index.html` — файла `COMPARISON_NOTES.md` нет и не было ни
в одной версии архива, которую видел я или которую цитировал разбор #179.
Не блокирует ни один AC (все содержательные факты, которые могли бы там
быть, взяты из реально существующих документов и подтверждены), но при
реализации кто-то потратит время, разыскивая несуществующий файл как
«третий по приоритету» источник истины. Снять правкой — убрать имя файла из
списка либо заменить на реально существующий (вероятно, опечатка/перенос из
не-#179 контекста).
### L2 — обязательный тег `Touch editor: …` присутствует по смыслу, но не дословно
**Файл:** `docs/specs/211-device-icons-visual-parity.md:183-186` (§8)
`docs/TOUCH-SUPPORT.md` («Documentation rule») требует, чтобы спецификации,
затрагивающие редактор, буквально называли один из трёх канонических тегов:
`Touch editor: supported` / `best effort / intentionally degraded` / `not
exposed`. §8 ТЗ №211 говорит «Device editor остаётся desktop-first / touch
best effort» — по смыслу корректно (совпадает с уже принятым в #179 «best
effort / intentionally degraded») и задача не меняет интерактивность
(в отличие от #179, где отсутствие этого тега было Medium именно потому, что
там вводился новый keyboard/focus контракт), поэтому не блокирует. Для
единообразия с остальными спецификациями и grep-совместимости стоит заменить
на буквальный `Touch editor: best effort / intentionally degraded.` — на
решение автора.
## Проверено и признано корректным
- **SHA-256 архива** совпадает с указанным в ТЗ; архив идентичен тому, что
проверялся в цикле #179.
- **Геометрия shell/core** (`1.26875`) и **value-badge pill** (`0.7875`
высота, `0.39375` радиус = половина высоты) — оба подтверждены прямым
измерением реальных `<path>`/`<rect>` координат, не переписаны на глаз.
- **Описание регрессии** (§3, пп. 1, 3, 4) сверено построчно с текущим
`src/styles.ts` и подтверждено буквально: `border-radius: 28%` (core не
круг), `border-radius: calc(... * 0.18)` при pill-высоте `0.7875` (радиус
должен быть `0.39375`), безусловный светлый `#BCBCBC` shell-stroke без
тёмного варианта.
- **Цвета состояний** (§7.3): hover `#0C82F0`, active/unlock `#F0A00C`,
alert `#F0410C`, Dark shell `#252525`/`opacity .75`, virtual
`stroke-dasharray 6 6`, selected `#F0A00C` ring `r=41.5`, focus `#0C82F0`
ring `r=41.5` поверх видимого base shell — все сверены построчным `grep`
по реальным SVG обеих тем и совпадают с таблицей §7.2/§7.3.
- **Корректно разрешённая ошибка пакета**: `Dark/Unlock.svg` в архиве
реально закрашен зелёным (`#1DC21D`, устаревшая dark-ревизия) — ТЗ №211
правильно, вслед за уже принятым решением владельца в #179, отвергает этот
файл в пользу «янтарный в обеих темах», а не проецирует его буквально.
- **Обязательные разделы §7.1 PROCESS.md** — все присутствуют: сценарий, что
видит пользователь до/после, проблема, скоуп/не-скоуп, контракт поведения,
UX/touch/доступность, данные/совместимость/i18n, AC1…AC10 с доказательством,
план автотестов, риски, откат, release-артефакты.
- **Скоуп корректно ограничен** восстановлением уже принятого дизайна #179 —
никаких новых состояний, resolvers, LQI-порогов, actions или config-модели
не вводится (§6); это отличает задачу от #179 и обосновывает отсутствие
открытых продуктовых вопросов владельцу без `blocked`.
- **Трассируемость**: `docs/specs/README.md` обновлён тем же коммитом с
двусторонней ссылкой issue↔ТЗ; коммит `93200eb` несёт трейлеры
`Issue: #211` и `User-Visible: no` — корректно для документации без
изменения продукта.
- **Секьюрность и touch-инвариант** не задеты: §8 явно называет secure
confirmation/keyboard/dialog focus return как поведение, которое обязано
остаться без изменений, а не переопределяет его.
## Чего не проверял
- **Figma-фреймы** (`99:1290`, `104:1539`) напрямую не открывались — ревью
ограничено содержимым скачанного архива, тем же источником, которым
пользовался автор ТЗ.
- **Полная построчная сверка всех Double/Text/LQI SVG всех четырёх сторон** —
выборочно проверены `Double Default Right.svg` (value pill) и
сопутствующий `Frame_2`; остальные три стороны и `Text *.svg` не
измерялись отдельно, поскольку геометрия pill и текста не зависит от
стороны по самому контракту §7.1 ТЗ.
- **PNG-визуализации архива** не открывались — не источник геометрических
фактов, только иллюстрация.
- **Производительность** не измерялась (кода нет).
- Гейты `typecheck`/`test`/`build`/smoke/golden не запускались — на этапе
ревью ТЗ продуктового кода не существует, раздел неприменим.
## Итог
Находка блокирующей силы не имеет: единственный Medium (M1) устраняется
точечной правкой текста ТЗ — либо явной ссылкой на источник и расчёт, либо
переносом числа в блок технических предположений §16, — без изменения
скоупа, AC или архитектурного решения. Два Low — на усмотрение автора.
Вердикт — жёлтый, возврат автору в рамках текущего issue.