From 3ccda408ba4803804714560646caee14ad740f5c Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Sat, 29 Aug 2026 07:48:53 +0000 Subject: [PATCH] docs: review document for #366 Issue: #366 User-Visible: no --- docs/reviews/SPEC-REVIEW-366-r2.md | 181 +++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 docs/reviews/SPEC-REVIEW-366-r2.md diff --git a/docs/reviews/SPEC-REVIEW-366-r2.md b/docs/reviews/SPEC-REVIEW-366-r2.md new file mode 100644 index 00000000..517d55d3 --- /dev/null +++ b/docs/reviews/SPEC-REVIEW-366-r2.md @@ -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`.