Files
houseplan-card/docs/reviews/SPEC-REVIEW-266-r3.md
T
2026-08-25 22:44:15 +00:00

172 lines
15 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-266-r3
Issue: [#266](https://github.com/Matysh/houseplan-card/issues/266) — «Рефакторинг 3/5: расщепить styles.ts»
ТЗ: `docs/specs/266-split-styles.md` (коммит `3a49b142`, ветка `issue/266-split-styles`)
Предыдущий раунд: SPEC-REVIEW-266-r2, вердикт жёлтый (Medium М2), ТЗ проверялось на коммите `afb6e151`
Этап: spec (PROCESS.md §2.4) · заход r3 · блокирующих циклов израсходовано 2/4
Вердикт: **зелёный**
## Скоуп ревью
Третий заход, разбор по дельте (PROCESS.md §2.10, issue #214). Предмет — изменения
ТЗ между `afb6e151` (на чём получен вердикт r2) и `3a49b142` (текущий HEAD):
```
git diff afb6e151..3a49b142 -- docs/specs/266-split-styles.md
```
Дельта — 4 строки: строка «Статус», AC2 (арифметика прототипа), AC6a (счёт
`prefers-reduced-motion`-блоков 8→10). Правка только текстовая, точечная,
адресует ровно находку M2 из r2 — не ребейз, не смена контракта поведения, не
новая подсистема, объём несопоставим с исходной задачей → полный повторный
разбор не требуется. Заново проверены AC2 и AC6a и всё, до чего дотягивается
эта дельта (числа, на которые они ссылаются, и юнит, который их фиксирует).
Остальной текст ТЗ наследуется из r2 без повторной проверки (раздел ниже).
**Важное отступление от обычного заходa этой стадии.** Между r2 и r3 в ветку
`issue/266-split-styles` дополнительно попали 6 коммитов реализации
(`cbdc2489`, `c684f178`, `7d094fd2`, `bf52524d`, `55f7126a`, `0d9320fe`) —
инструмент-генератор слайсов и все пять файлов `src/styles/*.styles.ts` плюс
финальный сборщик. Автор сообщил об этом честно в комментарии к ревизии 3:
подготовленные заранее коммиты реализации уехали в публикуемую ветку по
ошибке (несработавший `stash` перед `push`, унесённый ребейзом), историю
опубликованной ветки не переписывает. Разбор ниже — отдельным разделом
«Процессное замечание», не как находка по тексту ТЗ.
## Как проверялось
- Прочитан диф `afb6e151..3a49b142` целиком для `docs/specs/266-split-styles.md`
(выше) и полный текущий текст файла.
- Прочитан документ `docs/reviews/SPEC-REVIEW-266-r2.md` (коммит `34335d1e`) —
находка M2 и её формулировка.
- Арифметика AC2 пересчитана вручную: `248+381+540+1180+1359+19 = 3727`;
порог `3690×1.05 = 3874.5`; `3727 ≤ 3874.5` — сходится, разрыв r2 устранён.
- Поскольку реализация уже физически лежит в ветке (см. отступление выше),
числа AC2 и AC6a сверены не только с текстом ТЗ, но и с фактическим кодом —
строгая проверка, а не совпадение на слово автора:
- `wc -l src/styles.ts src/styles/*.styles.ts` → `19 / 248 / 381 / 540 /
1180 / 1359` — совпадает с AC2 буквально, каждый файл под лимитом 1650,
сумма 3727 под порогом 3874;
- `grep -c '@media (prefers-reduced-motion: reduce)'` по пяти новым файлам
→ 10 совпадений (`base.styles.ts`:1, `chrome.styles.ts`:1,
`devices.styles.ts`:2, `plan.styles.ts`:6); `grep` того же паттерна по
`src/styles.ts` на коммите r2 (`afb6e151`, до переноса) → тоже 10 — AC6a
«10» верен, старые «8» из r1/r2 были ошибкой счёта, как и признаёт текст;
- `@media (forced-colors: active)` — 2 блока и до, и после (в
`plan.styles.ts`, строки 314 и 1189) — совпадает с AC6a;
- прочитан `test/styles-split.test.mjs` — юнит буквально реализует то, что
AC4/AC5/AC6a описывают (порядок сборщика, непересечение селекторов со
списком исключений, счёт медиа-обёрток 2/10), и способен упасть: любое из
трёх чисел, порядок массива или лишний общий селектор ломает assert.
- Проверено наличие `demo/smoke_plan_snap_overlay.mjs` и `demo/smoke_preloader.mjs`,
названных в §7 ТЗ как обязательные на слайсах `plan`/`base` — оба файла на
месте.
- process-gate прогнан для диагностики процессного замечания (см. ниже):
`node scripts/process-gate.mjs --issues` → `FAIL п.8 статус issue — issue
#266: статус S4-spec-review, а нужен один из S5-ready / S6-in-progress /
S7-code-review / S8-merged`.
## Закрытие раунда r2
| Находка r2 | Чем закрыта | Где видно |
|---|---|---|
| **M2** (Medium, в скоупе) — AC2 «факт» 4431 строка не проходил собственный порог 3874.5, разрыв не объяснён | AC2 переписан: источник роста назван явно (пустые строки-разделители генератора-прototipa), приведён уплотнённый замер 248/381/540/1180/1359+19=3727 ≤ 3874 | `docs/specs/266-split-styles.md`, AC2 (диф `afb6e151..3a49b142`); арифметика и цифры перепроверены против фактических файлов `src/styles/*.styles.ts` (раздел «Как проверялось») — совпадают буквально |
Побочно, вместе с M2, автор поправил и AC6a (счёт `prefers-reduced-motion` 8→10) —
это не было находкой r2 (r2 унаследовал L2-риск как «не критично»), но правка
корректна и подтверждена: фактический счёт в источнике на момент r2 (`afb6e151`)
и сейчас — 10, «8» было ошибкой обоих предыдущих раундов, как и пишет автор.
## Унаследовано из r2
Без повторной проверки, документ `docs/reviews/SPEC-REVIEW-266-r2.md` на `afb6e151`:
- §0 (сценарий), §1.1 (структура каталога, распределение по кластерам),
§1.2 (сборщик, внешний контракт `cardStyles`) — не тронуты дельтой r2→r3;
- §1.3.1–§1.3.4 (golden как главный критерий, запрет дубликатов, порядок
склейки, бюджет бандла) — не тронуты;
- §1.3.5/§1.3.6 (scope-ключ сверки, обязательные смоки `forced-colors`/
`reduced-motion`) — унаследованы из r2, который сам унаследовал их как
закрытие M1 из r1 (`SPEC-REVIEW-266-r1.md` на `4c93f28e`);
- §1.4 (порядок слайсов), §2 (скоуп/не-скоуп), §3 (UX/i18n/touch), §4 (риски),
§5 (release-артефакты), §8 (откат) — не тронуты;
- AC1, AC3, AC4, AC5, AC6, AC7, AC8 — текст не менялся дельтой r2→r3;
доказательства AC4/AC5/AC6a перепроверены заново в этом раунде (см. выше),
поскольку дельта их задевала через AC6a; AC1/AC3/AC6/AC7/AC8 наследуются
без повторной проверки;
- классификация «класс A, полный флоу», обязательные разделы §7.1 — приняты
в r1, не пересматривались.
## Процессное замечание (не находка по ТЗ, не блокирует вердикт)
Между r2 и r3 в ветку попали 6 коммитов реализации класса A (`src/**`):
инструмент `scripts/dev/styles-split.mjs` и пять файлов
`src/styles/*.styles.ts` + финальный сборщик `src/styles.ts` — то есть
продуктовый код написан и закоммичен, пока issue #266 находится в статусе
`S4-spec-review`, раньше «Готово к разработке». Это прямое совпадение с
формулировкой PROCESS.md §12: «Запрещено: код без issue или из статуса
раньше «Готово к разработке»».
Автор сообщил об этом сам и честно (комментарий к ревизии 3): заранее
подготовленные коммиты реализации уехали в публикуемую ветку по ошибке
(несработавший `stash` перед `push`, унесённый последующим ребейзом), история
опубликованной ветки не переписана. Намеренного нарушения или сокрытия нет.
Тем не менее это стоит зафиксировать отдельно, а не просто отметить в тексте
ревью (§12: «оставили в тексте ревью» закрытием не считается — этот принцип
для находок out-of-scope, но по духу применим и здесь, раз правило нарушено
буквально). Дополнительно: механическая проверка это правило действительно
умеет ловить (`node scripts/process-gate.mjs --issues` → `FAIL п.8`), но
только пока метка issue равна текущей `S4-spec-review`. Как только этот
вердикт станет зелёным и метка перейдёт в `S5-ready` (штатный следующий шаг),
повторный прогон того же гейта на тех же коммитах пройдёт зелёным — проверка
п.8 сверяет **текущую** метку issue с диапазоном коммитов, а не метку на
момент, когда коммит был написан. То есть нарушение, которое сейчас поймано
случайно (ревью совпало по времени с окном, где метка ещё не сдвинулась),
станет невидимым естественным ходом процесса — ровно случай из PROCESS.md
§12: «если правило удалось нарушить незаметно, виновата проверка».
Завёл отдельный issue с меткой `process` (не блокирует эту задачу и не входит
в бюджет циклов #266): **#311** «process-gate п.8 проверяет текущую метку
issue, а не метку на момент коммита — код #266 обгонит собственную DoR
незаметно».
Это не находка по содержанию ТЗ — сам документ `docs/specs/266-split-styles.md`
не пишет и не подтверждает несуществующее поведение задним числом; наоборот,
случайно попавшая реализация дала возможность сверить AC2/AC6a не с оценкой
автора, а с фактическим кодом (см. «Как проверялось»), что только укрепило
уверенность в ревизии 3. Вердикт по ТЗ не меняется этим замечанием.
## Что проверено и корректно
- Оба обязательных первых раздела (§0 «Сценарий», «Что человек увидит») на
месте и не тронуты дельтой — задача refactor-only, продуктового поведения
нет, сформулировано честно ещё в r1 и не оспаривалось.
- Все обязательные разделы §7.1 присутствуют (структура, скоуп/не-скоуп,
контракт, UX/данные/i18n/touch, AC1…AC8 с доказательством у каждого, план
автотестов, риски, откат, release-артефакты).
- Догадок, выданных за факт, не найдено: единственное новое утверждение
ревизии 3 (счёт reduced-motion-блоков «10», источник роста прототипа) явно
подтверждено способом получения (`grep -n` по исходнику) и совпадает с
фактическим кодом ветки.
- Арифметика AC2 сведена и корректна (пересчитано вручную и против кода).
- Открытых продуктовых вопросов нет.
## Чего не проверял
- Тяжёлые гейты (`typecheck`/`test`/`build`/`golden`/смоки/мутационный
гейт) прогонами не запускал. Дельта этого раунда — 4 строки текста ТЗ, для
которых это несоразмерно; сами гейты и полный код — предмет код-ревью
(`S7-code-review`), которое ещё не началось (issue не покидал S4).
Совпавшие с этим раундом коммиты реализации сверил точечно (`wc -l`, `grep`,
чтение `test/styles-split.test.mjs`) ровно в объёме, нужном для проверки
AC2/AC6a этого ТЗ, а не как код-ревью — полный аудит реализации (стиль,
покрытие мутационного гейта, побочные правки в `scripts/fix-test-build.mjs`
и `scripts/mutation-gate.mjs`) будет сделан на своём этапе.
- Не проверял, синхронизированы ли три копии бандла (`dist/`,
`custom_components/houseplan/frontend/`, `demo/srv/assets/`) — не предмет
спек-ревью.
- Не запускал `demo/smoke_plan_snap_overlay.mjs` / `demo/smoke_preloader.mjs`
сам — только подтвердил их существование; коммит-сообщения слайсов 4 и 5
заявляют «OK», перепроверка результата смоков — код-ревью.