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

195 lines
18 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-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 → в задаче
---
<!-- material-anchors: сгенерировано конвейером (#414) -->
## Материал раунда
- Ветка: `dev`, коммит `8afba7e6edb5` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
- Дерево материала: `2acfb9ec47f68cd0c479f34c772597bb4569e96a`
```
git log --all --format='%H %T' | grep 2acfb9ec47f6
```
- Тело issue: `12e66588332b94c78100156f01e4832881b8163fb6f8fdca83acfcb8e90f4545`
- Вердикт конвейера: `green` · High 0