Files
houseplan-card/docs/reviews/SPEC-REVIEW-366-r2.md
T
2026-08-29 07:48:53 +00:00

182 lines
17 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-366-r2
Issue: #366 — «Glow #20: движущиеся ворота на cover-сущности вызывают до ~100
пересчётов геометрии света за одно открытие»
Этап: ТЗ на ревью (S4-spec-review), лёгкий трек (`small`)
Заход: r2 · блокирующих циклов ревью ТЗ израсходовано 1 из 2 (лимит §4 для лёгкого трека)
Материал: тело issue #366 на момент ревью (ревизия 2), дерево `dev` на SHA
`c50d9e42903921589eca8dc90c113ca329e3c6f5`
Предыдущий раунд: `docs/reviews/SPEC-REVIEW-366-r1.md`, вердикт жёлтый, материал —
дерево `dev` на SHA `f2e365726a6e28a9acf03b6a37b4d2099770229d`
Вердикт: **зелёный**
## Скоуп раунда
Разбор по дельте (§2.10 PROCESS.md), а не заново. Артефакт ТЗ живёт в теле
issue (small-трек), поэтому формального `git diff` файла нет; дельта
установлена тремя способами и все три сходятся:
1. футер ревизии 2 сам перечисляет изменения: «M1 — AC4 называет реальный
`smoke_glow.mjs`... M2 — визуальная ступенчатость явно помечена как
принятое предположение... Low: строки уточнятся по факту в код-ревью;
`docs/LIGHT.md` §Caching добавлен в release-артефакты реализации»;
2. прямое сравнение текущего тела issue с фрагментами, процитированными в
`SPEC-REVIEW-366-r1.md`: разделы «Проблема», «Направление фикса»,
«AC-кандидаты», К1, К2, AC1/AC2/AC3/AC5, «Откат» byte-идентичны цитатам r1
— менялись только формулировка AC4 и добавленный блок «Принято
предположительно»;
3. `git diff f2e365726a6e28a9acf03b6a37b4d2099770229d..HEAD --stat -- src/logic.ts src/houseplan-card.ts demo/smoke_glow.mjs demo/smoke_junction_limits.mjs docs/LIGHT.md`
— пусто. Дерево `dev` для всех файлов, на которые опирался r1, не сдвинулось
ни на строку между SHA r1 и текущим HEAD (три коммита между ними — доки по
#369 и публикация самого `SPEC-REVIEW-366-r1.md`, продукта не касаются).
Значит это не ребейз на ушедший вперёд `dev` (§2.10 «разбор остаётся
полным, если...») — условие для сокращённого разбора выполнено, а не
просто заявлено.
Дельта локальна и мала по объёму относительно исходного ТЗ: правка текста
одного AC и добавление одного маркирующего абзаца. Новая подсистема не
задета, контракт (К1/К2, формула квантования, единственная точка применения)
не менялся. Полный повторный разбор не требуется.
## Как проверялось
Дельта проверена по существу, не на слово автора:
- **M1** (было: AC4 называл несуществующий `smoke_door_glow*` плюс
необоснованный `smoke_junction_limits`). Текущий AC4: «существующие
смоки/golden #20 зелёные без правки ассертов — прежде всего
`demo/smoke_glow.mjs` (строки ~598-631 уже гоняют `current_position`
0/50/100 — все узлы сетки 0.05) плюс полный смок-набор по smoke-select
дельты». Прочитал `demo/smoke_glow.mjs:598-631` — `setDoorPosition(0)` на
:627 и `setDoorPosition(50)` на :629, начальный `current_position: 100` на
:360 (`glow_dynamic_door` через `current_position` реально существует и
реально использует доли 0/0.5/1.0 — узлы сетки 0.05 из К1). Название файла
и утверждение о его содержимом точны. Ссылка на `smoke_junction_limits` без
обоснования убрана, вместо неё — отсылка на инструмент выбора смоков по
дельте (`scripts/smoke-select.mjs`), который и предназначен закрыть этот
класс вопроса, когда код появится. **M1 закрыта по существу, не просто
переформулирована.**
- **M2** (было: «5% неразличимо» подано фактом, не пометкой). Текущий текст
содержит отдельный абзац: «**Принято предположительно (r1-M2):** визуальная
цена — вырез света ступает по 5% длины проёма. Предположение: ... Если
полевые впечатления владельца после беты скажут обратное — квант
уменьшается правкой одной константы (0.02 ⇒ ≤51 пересчёт) либо решение
пересматривается в сторону debounce; цена отката — один revert.» Это ровно
формат «принято предположительно, поменять свободно» из §7.1, названо явное
условие пересмотра и цена отката. **M2 закрыта.**
- **L1** (номера строк в ТЗ отстали от `dev`). Автор явно отложил до
код-ревью («строки уточнятся по факту»), не стал переписывать текст ТЗ.
Проверил актуальность: поскольку `houseplan-card.ts` не менялся между SHA
r1 и текущим HEAD (см. diff --stat выше), расхождение то же самое, что было
на r1 (было −1 к номеру), не выросло. Отложенное решение приемлемо: Low
находится на усмотрение ревьюера, а номера строк реализация всё равно
сверит перед кодом.
- **L2** (`docs/LIGHT.md` не назван в release-артефактах). Футер ревизии 2
утверждает «`docs/LIGHT.md` §Caching добавлен в release-артефакты
реализации» — проверил текст всего тела issue (`grep -in "light.md\|release"`
по полному телу): единственное вхождение `LIGHT.md` — сама эта фраза в
футере. В основном тексте ТЗ (раздел «User-Visible») по-прежнему только
«changelog en+ru», отдельного упоминания `docs/LIGHT.md` в тексте контракта
или отката нет. **Заявление футера не подтверждено текстом документа** —
см. находку L2′ ниже.
- К1/К2/AC1/AC2/AC3/AC5/откат — не перепроверялись заново по существу
(наследуются из r1, см. раздел ниже), т.к. дельта их текста не касается и
дерево `dev`, от которого зависела их проверка, не двигалось.
## Находки
Находок, блокирующих цикл (High или Medium в скоупе без ответа), нет.
### L2′ (Low, не блокирует) — расхождение футера ревизии 2 с фактическим текстом ТЗ
Футер ревизии 2 заявляет, что `docs/LIGHT.md` §Caching добавлен в
release-артефакты реализации. По факту в теле issue такой записи нет —
раздел «User-Visible» называет только changelog en+ru, отдельного упоминания
`docs/LIGHT.md` как обязательного release-артефакта нет ни в контракте, ни в
разделе отката.
**Почему Low:** предыдущая находка L2 (r1) была необязательной («правится
либо снимается решением ревьюера с записью, если сочтёт достаточным
changelog»). Обновление канонического документа подсистемы при смене
контракта сигнатуры всё равно требуется по DoR (§2.5 «release-артефакты...
документация») и будет проверено на код-ревью независимо от текста ТЗ —
неточность футера не создаёт риска пропустить реальную правку `LIGHT.md`,
только неточно описывает, что уже сделано на этапе ТЗ.
**Диспозиция:** снимаю без правки текста ТЗ, с записью здесь. Требование к
разработчику остаётся: при реализации обновить `docs/LIGHT.md` §Caching
числовым шагом квантования (0.05) тем же коммитом, что и код — это проверит
код-ревью (S7), а не повторный цикл ревью ТЗ.
## Закрытие раунда r1
| Находка (r1) | Чем закрыта | Где видно |
|---|---|---|
| **M1** — AC4 называет несуществующий/необоснованный смок | AC4 переписан: называет реальный `demo/smoke_glow.mjs` (проверено: строки 598-631 действительно двигают `current_position` через 0/50/100, узлы сетки 0.05) + отсылка к `smoke-select.mjs` вместо необоснованного `smoke_junction_limits` | Тело issue #366, раздел «AC и доказательства», пункт **AC4** |
| **M2** — визуальная ступенчатость подана фактом, не предположением | Добавлен абзац «Принято предположительно (r1-M2)» с явным условием пересмотра и ценой отката | Тело issue #366, между К2 и «AC и доказательства» |
| **L1** — номера строк в ТЗ отстали от `dev` | Не исправлено текстом; автор явно отложил до код-ревью. Расхождение не выросло — `houseplan-card.ts` не менялся с r1 (см. `git diff --stat` в разделе «Как проверялось») | Футер ревизии 2: «строки уточнятся по факту в коде-ревью» |
| **L2** — `docs/LIGHT.md` не назван в release-артефактах | **Не закрыта фактически**, несмотря на заявление футера — см. находку L2′. Снимается как Low с явной запиской, требование переносится на код-ревью | Футер ревизии 2 vs тело issue (нет строки в разделе User-Visible) |
## Унаследовано из r1
Без повторной проверки принято из `docs/reviews/SPEC-REVIEW-366-r1.md`
(SHA `f2e365726a6e28a9acf03b6a37b4d2099770229d`), поскольку дельта этого
раунда их текста не касается, а код, на котором строилась проверка, не
изменился (`git diff --stat` пуст для `src/logic.ts`,
`src/houseplan-card.ts`, `demo/smoke_glow.mjs`, `docs/LIGHT.md` между тем SHA
и текущим `HEAD`):
- Локализация проблемы (`openingLightStateSignature`,
`src/logic.ts:344-357`, `amount.toFixed(3)`) и её причина (cover
`current_position` в процентах даёт новую сигнатуру на каждый процент хода);
- Соответствие `docs/SCOPE.md` (починка перф-дефекта в рамках J1/J7, не новая
функция) и обоснованность small-трека (одна поверхность, геометрия/миграции
не тронуты);
- К1 — единственная точка квантования (`passageStates`,
`src/houseplan-card.ts:10352-10361` на момент r1) реально питает и
сигнатуру, и длину выреза, и partition-cut — принцип «одно число — один
источник» (§8 PROCESS.md) соблюдён архитектурно;
- К2 и математика квантования: сетка 0.05 на [0,1] даёт ровно 21 узел;
`Math.round(clamp(x)/0.05)*0.05` даёт `0.30`/`0.31` → один и тот же узел,
`0.30`/`0.33` → разные, `NaN/-1/2` → корректный зажим — проверено в r1
прямым расчётом, формула в теле issue не менялась;
- AC1 (юнит на `quantizeOpeningLightAmount`), AC2 (≤21 сигнатура на свипе),
AC3 (binary-двери байт-в-байт — квантование стоит выше
`openingLightStateSignature`, существующие юниты её не заденут), AC5
(мутант «квант → identity» красит AC2 детерминированно) — тексты AC1-3,5 не
менялись между r1 и r2, проверка r1 остаётся в силе;
- Откат (один revert, кэш самоинвалидируется сигнатурой, конфиг не участвует)
— текст не менялся;
- `User-Visible: yes` с обоими changelog — учтено верно (с оговоркой L2′ про
`LIGHT.md` выше, которая новая для этого раунда).
## Что проверено и корректно (этот раунд)
- Обе Medium-находки r1 закрыты предметно: правка текста, а не риторическая
переформулировка — проверено чтением файла-доказательства (`smoke_glow.mjs`)
и текста добавленного абзаца допущения;
- Дерево `dev`, от которого зависела проверка r1, не двигалось — условие
«разбор остаётся полным при ребейзе» неприменимо, сокращённый разбор
правомерен;
- Новых Medium/High находок делта не создала.
## Чего не проверял
- Код не написан — `typecheck`/`test`/`build`, `npm run golden:verify`,
`node scripts/model-invariants.mjs`, смоки браузером — не мой гейт на этапе
ревью ТЗ, предмет S7 (код-ревью). Дешёвые гейты не гонял: делта этого
раунда — текст issue, `src/**` не тронут.
- Не проверял глазом визуальную неразличимость 5%-ступени в браузере —
унаследовано из r1 как оценка правдоподобия, теперь явно помеченная в самом
ТЗ как предположение с планом пересмотра, что и было целью M2.
- Не проверял, будет ли `docs/LIGHT.md` реально обновлён при реализации — это
требование переносится на код-ревью (см. L2′).
## Вердикт
Обе блокирующие Medium-находки r1 закрыты по существу и проверяемо. Новых
находок делта не породила, кроме одной некритичной (L2′, footer расходится с
телом issue, снята с запиской). Технический контракт и AC остаются
доказуемыми в объёме, установленном r1. Issue готово к переходу в
`S5-ready`.