mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
@@ -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`.
|
||||
Reference in New Issue
Block a user