docs: review document for #366

Issue: #366
User-Visible: no
This commit is contained in:
claude[bot]
2026-08-29 07:48:53 +00:00
parent a2c189eaa3
commit 3ccda408ba
+181
View File
@@ -0,0 +1,181 @@
# 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`.