Files
houseplan-card/docs/reviews/SPEC-REVIEW-532-r2.md
T
2026-09-11 16:05:14 +00:00

18 KiB
Raw Blame History

SPEC-REVIEW-532-r2

Issue: #532 · Этап: ТЗ на ревью (S4-spec-review) · Заход r2 · блокирующих циклов израсходовано 0/4 (r1 — зелёный, бюджет не тратит, #227)

Скоуп ревью

Материал — тело issue #532, раздел ## ТЗ, редакция r2 (комментарий автора «ТЗ r2 — на ревью», 2026-09-11T15:56:10Z). Это не первый заход, но контракт изменился по существу (К2 переписан, AC3 переписан), поэтому по PROCESS.md §2.10 разбор веду полным, а не только по находкам r1 — причина: «смена контракта поведения», один из явных критериев, требующих полного разбора. Основание: r1 получил зелёный вердикт на К2 «golden останется зелёным» (комментарий ревьюера от 2026-09-11T15:31:18Z), затем автор сам вернул задачу в S3-spec, потому что реализация это обещание опровергла (комментарий «Возврат в S3-spec: К2 опровергнут замером», 15:54:23Z). Это не находка ревью — обещание опровергла сама реализация, автор зафиксировал это честно и переписал контракт, не подгоняя факт под старый текст.

Точную дельту r1→r2 получил не из пересказа, а из истории редактирования тела issue (gh api graphql → Issue.userContentEdits, три снимка: до появления ## ТЗ, редакция r1, редакция r2) и построил diff -u между снимками r1 и r2.

Как проверялось

Читал в порядке из инструкции: docs/SCOPE.md, PROCESS.md (§1–§10.3), AGENTS.md, тело issue #532 целиком (симптом → замер → аналитика → ТЗ) и все 5 комментариев, docs/SUN.md (канонический документ фона, раздел «Current four-phase background»). Технические утверждения ТЗ сверял с кодом на дереве dev@8afba7e6 (рабочая копия):

  • src/styles/plan.styles.ts:89-96 — селектор и стопка drop-shadow дословно совпадают с К1/К2 (.stage.daycycle .hp-paperg, .hp-static-stage.daycycle .hp-paperg); правки ещё нет, дерево в состоянии «до» задачи — ожидаемо для стадии ТЗ;
  • demo/golden/matrix.mjs:6 — пороги сцены stage: maxChannelDelta: 10, maxDiffRatio: 0.0005, ровно те, о которые разбивается К2 (3.43 % на day-cycle-night-dark — превышение в ~68 раз, как и пишет автор);
  • demo/golden/matrix.mjs:458-472 — ровно 4 сцены с bgMode: 'daynight' во всей матрице (day-cycle-{dawn,day,dusk,night}-dark), других нет; отсюда утверждение К2 «никакой другой кадр матрицы измениться не имеет права» проверяемо и заявление АС3 «ровно четыре» структурно верно — играть могут только эти четыре записи;
  • src/glow-blend.ts:61 — svgScreenBlendSupported действительно рантайм- проба, не читает bg_mode — подтверждает К4 кодом, а не только измерением (унаследовано из r1, но перепроверил сам, это дёшево);
  • docs/SUN.md:59-86 — раздел «Current four-phase background» пока не содержит упоминания композиционного слоя контура: правка AC5 добавляет новую строку, а не противоречит существующей; стиль совпадает с уже имеющимися архитектурными утверждениями раздела (например, про группировку контура «outside the grouped plan-paper footprint»), так что место для этого факта в каноне — правильное;
  • scripts/smoke-select.mjs:1-45 — isExecutableFrontend считает .ts-файл исполняемым, значит plan.styles.ts инструмент разберёт; но извлекает он символы, а изменённая строка — чистая CSS-декларация (will-change: filter;) без идентификаторов проекта. Заявление риска 5 «селектор честно отвечает «неопределённость»» правдоподобно по механике инструмента (нет символа для точного совпадения, а «filter» как слово слишком частый, чтобы пройти BROAD_SHARE); автор не выдаёт это за факт, а обещает прогнать и назвать результат в хендоффе — это ровно то, что требует процесс;
  • проверил, что demo/smoke_daycycle_raster.mjs и demo/benchmark_daycycle_raster.mjs в дереве действительно отсутствуют — ТЗ корректно называет свидетеля «создаётся», а не существующим.

Не гонял ни одного гейта: на этапе ТЗ материал — текст, а не код; гейты исполнимого кода к этому раунду не относятся (кода ещё нет — реализация, проваленная в предыдущей попытке, не смержена, git log подтверждает: на dev нет коммита #532).

Находки

Нет. Ни одной блокирующей или требующей правки в скоупе задачи.

Рассмотренные и снятые как небеспроблемные кандидаты (перечисляю, потому что процесс требует не прятать сомнение, а не потому что они стали находками):

  1. Порог бюджета 2.0 против переизмеренного «здорового» отношения 0.82 — запас всего ~2.44×, у′же, чем на «около восьмикратный» из r1 (там был 0.26). Автор сам скорректировал формулировку риска 4 (убрал «восьмикратный запас», оставил «большой запас») — то есть не скрыл сужение. Порог отмечен как «принято предположительно, менять свободно» — ревьюер вправе спорить, и я не вижу оснований спорить: 2.0 всё ещё далеко и от здорового (0.82), и от больного (15.06) значения, а фактический шум CI будет виден на реальном прогоне свидетеля в код-ревью.
  2. AC3 экстраполирует порог «сдвиг среднего цвета ≤0.1/255» на все четыре кадра, хотя пиксельно автор разобрал только day-cycle-night-dark (сдвиг 0.07) — для остальных трёх есть только «все четыре разошлись» без разбора. Это не догадка, выданная за факт: у AC3 явный красный триггер («пятый разошедшийся кадр либо сдвиг среднего цвета — находка ревью»), значит фактическую проверку для всех четырёх кадров сделает код-ревью на реальном артефакте golden, а не эта редакция ТЗ. Контракт проверяем, а не голословен.
  3. .hp-static-stage.daycycle .hp-paperg (houseplan-space-card) получает ту же подсказку, но ни одна сцена матрицы её не использует с bgMode: daynight — по коду это существующий пробел покрытия golden, не появившийся из-за этой задачи и не расширяемый ею;К1 намеренно трогает оба селектора одним правилом, а не только .stage. Не блокирует.
  4. Отложенная пересъёмка эталонов оставляет dev/nightly golden красным до коммита на кандидате беты. Это не самодеятельность автора: тот же механизм (Release: + Baseline-Reviewed:, golden:accept --reviewed) уже используется в проекте буквально соседним коммитом (f65d07e3 Принять три PDF-эталона, которые изменил #530). Риск назван в ТЗ явно (риск 2), цена не спрятана.

Закрытие раунда r1

r1 (docs/reviews/SPEC-REVIEW-532-r1.md, зелёный, материал — тело issue до правки 2026-09-11T15:55:49Z) не вернул находок — цикл не был потрачен. Возврат в S3-spec произошёл не по вердикту ревью, а по решению автора после того, как собственная реализация опровергла обещание К2. Формально закрывать нечего, но фиксирую, чем именно старое К2 расходится с новым и почему это не недоработка автора, а корректная реакция на новый факт:

Что было в r1 Что показала реализация Чем закрыто в r2
К2: «вид не меняется ни на пиксель сверх порога»; golden обязан остаться зелёным при maxChannelDelta: 10 4 кадра day-cycle-*-dark разошлись, day-cycle-night-dark — 3.43 % пикселей, превышение maxDiffRatio в ~68 раз К2 переписан: вид не меняется содержательно (ореол снаружи плана байт-в-байт, средний цвет кадра 176.59→176.66), но 4 эталона пересматриваются на кандидате беты
AC3: «четыре golden-кадра не изменились», проверка — golden:verify на полной матрице Тот же прогон красный AC3 переписан: «изменились ровно четыре, и вот чем» — список кадров + срез ореола + средний цвет; пятый кадр или больший сдвиг — красный
Риск 3 (r1): «Golden. Порог сцены 10, кадры обязаны остаться зелёными» Не подтвердилось Риск заменён на «Пересъёмка эталонов стоит руки владельца» — цена, а не гарантия
Порог бюджета 2.0 на числах 7.9/0.26 (демо-стенд, ховер) Реальный смок на панораме дал другие абсолютные числа (15.06/0.82) Числа в «Принято предположительно» обновлены на измеренные смоком, порог 2.0 оставлен — по-прежнему с запасом в обе стороны

Унаследовано из r1

Без повторной проверки принято на слово из r1 то, чего дельта не касается, но я всё же перепроверил дешёвые из этих утверждений сам (см. «Как проверялось») вместо слепого наследования, так как они стоили пары grep:

  • К1 (правило will-change: filter на связке двух селекторов, ограничено классом daycycle) — не менялось между r1 и r2 текстуально; перепроверил код (plan.styles.ts:89-96) сам, а не унаследовал.
  • К3 (четыре слоя окружения вне скоупа) и К4 (экранный блендинг вне скоупа, svgScreenBlendSupported — рантайм-проба) — не менялись; К4 перепроверил кодом сам.
  • К5 (бюджет — отношение, а не абсолютные мс) — не менялся текстуально.
  • AC1, AC4 (вычисленный стиль .hp-paperg с/без will-change в двух режимах фона) — не менялись по существу (только словесная правка «новый смок» → «смок» и точное число в столбце AC2 вместо оценки «около 8»).
  • AC5 (документация docs/SUN.md + оба changelog) — не менялся.
  • Продуктовая рамка, скоуп/не-скоуп, откат (кроме добавленной фразы про эталоны) — не менялись.
  • Источник: docs/reviews/SPEC-REVIEW-532-r1.md, материал — тело issue на снимке до 2026-09-11T15:55:49Z (см. userContentEdits, узел 0, дерево dev@116cfd5f на момент r1).

Что проверено и корректно

  • Полнота разделов по PROCESS.md §7.1: сценарий и «до/после» — первые в блоке ТЗ; проблема разобрана выше ## ТЗ (симптом, решающий опыт, замер) и ТЗ на неё явно ссылается; скоуп/не-скоуп — «Чего задача не трогает»; контракт — К1–К5; i18n, миграция, touch — закрыты одним перечислением «не трогает» (bg_mode и его миграции, i18n, touch-контракт); план автотестов и AC — таблица AC1–AC5 с «чем краснеет» у каждого; риски — 5 штук, включая новый; откат — есть; release-артефакты — changelog RU+EN, docs/SUN.md, отдельный коммит эталонов на кандидате беты.
  • Трек: полный, критерий §5, который задача не проходит, назван явно («нет влияния на производительность»).
  • Ни одного продуктового вопроса владельцу не поднято и не нужно: все открытые места (порог 2.0, will-change: filter vs transform, permanent vs on-gesture, движок свидетеля) — технические, помечены «принято предположительно, менять свободно», и я как ревьюер с ними согласен по существу (см. «Как проверялось»).
  • Не найдено ни одной догадки, выданной за факт: там, где вывод не доказан на 100 % (антиалиасинг штриховки как причина, а не что-то ещё), автор дал контрольный эксперимент (тот же эффект с transform вместо filter) и явный красный триггер в AC3, а не декларацию «это точно так».

Чего не проверял

  • Не выполнял ни одного гейта (typecheck/test/build/golden) — на этой стадии кода нет, гонять нечего; дерево dev@8afba7e6 не содержит правки #532 (реализация из провалившейся попытки не смержена).
  • Не перепроверял сам сырые числа профиля Firefox с машины владельца (объективно недоступны) — принимаю их как входные данные симптома, не как предмет этого ревью.
  • Не проверял, действительно ли will-change в реальном Gecko владельца будет принят движком (риск 1) — это заявлено и ТЗ, и мной как непроверяемая до реализации/профиля неопределённость, а не блокирующий пробел контракта.

Вердикт

Вердикт: зелёный · заход r2 · блокирующих циклов 0/4 · High: 0 · Medium: 0 → в задаче


Материал раунда

  • Ветка: dev, коммит 8afba7e6edb5 — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
  • Дерево материала: 2acfb9ec47f68cd0c479f34c772597bb4569e96a
    git log --all --format='%H %T' | grep 2acfb9ec47f6
    
  • Тело issue: 12e66588332b94c78100156f01e4832881b8163fb6f8fdca83acfcb8e90f4545
  • Вердикт конвейера: green · High 0