From 0d62a48b1eb0fb98b3002cb23d660bd43c64fc0e Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Tue, 25 Aug 2026 22:44:15 +0000 Subject: [PATCH] docs: review document for #266 Issue: #266 User-Visible: no --- docs/reviews/SPEC-REVIEW-266-r3.md | 171 +++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 docs/reviews/SPEC-REVIEW-266-r3.md diff --git a/docs/reviews/SPEC-REVIEW-266-r3.md b/docs/reviews/SPEC-REVIEW-266-r3.md new file mode 100644 index 00000000..5c954a40 --- /dev/null +++ b/docs/reviews/SPEC-REVIEW-266-r3.md @@ -0,0 +1,171 @@ +# 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», перепроверка результата смоков — код-ревью.