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

15 KiB
Raw Blame History

SPEC-REVIEW-266-r3

Issue: #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», перепроверка результата смоков — код-ревью.