Files
houseplan-card/docs/reviews/SPEC-REVIEW-531-r2.md
T
claude[bot] d21797dc66
Проверка (CI) / Классификация изменённых файлов (push) Successful in 26s
Проверка (CI) / Мутанты по диффу (1/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Мутанты по диффу (2/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Мутанты по диффу (3/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Мутанты по диффу (4/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Мутанты по диффу (5/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Мутанты по диффу (6/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Предполётные проверки: документация, провенанс, процесс (push) Failing after 52s
Проверка (CI) / HACS: валидация репозитория (push) Failing after 24s
Проверка (CI) / Hassfest: манифест интеграции (push) Failing after 25s
Проверка (CI) / Переиспользование: это дерево уже проверено (push) Successful in 43s
Проверка (CI) / Бэкенд: pytest в Home Assistant (push) Failing after 4m59s
Проверка (CI) / Фронтенд: типы, юниты, мутанты, синхрон бандла (push) Failing after 7m4s
Проверка (CI) / Смоки в браузере (шард 1 из 3) (push) Skipped
Проверка (CI) / Смоки в браузере (шард 2 из 3) (push) Skipped
Проверка (CI) / Смоки в браузере (шард 3 из 3) (push) Skipped
Проверка (CI) / Смоки: все шарды зелёные (push) Skipped
Проверка (CI) / Golden-кадры против принятых эталонов (push) Skipped
Проверка (CI) / Перф-смок: бюджет времени кадра (push) Skipped
docs: review document for #531
Issue: #531
User-Visible: no
2026-09-11 10:02:27 +00:00

14 KiB
Raw Blame History

SPEC-REVIEW-531-r2

Issue: #531 — «Панорама плана в Firefox: viewBox переписывается на каждый кадр жеста, композитор ждёт 13 vsync-тиков» Этап: spec (ревью ТЗ, PROCESS.md §2.4) Трек: полный (не изменился со времени r1 — критерий §5, который задача не проходит, назван и подтверждён в r1: «нет влияния на производительность») Заход: r2 · блокирующих циклов израсходовано 1 из 4 Материал: тело issue #531 на текущем HEAD, dev b4a16ad7. Продуктовый код не тронут: git diff af2081cb..b4a16ad7 -- src/live-viewport.ts src/live-interaction-runtime.ts src/houseplan-card.ts docs/ARCHITECTURE.md scripts/mutation-gate.mjs test/live-viewport.test.mjs demo/benchmark_large_house.mjs пуст. Единственный коммит между материалом r1 и этим раундом — b4a16ad7 docs: review document for #531 (класс C, публикация самого документа r1), никакого влияния на технические утверждения r1.

Разбор по дельте (PROCESS.md §2.10)

Предыдущий раунд закончился жёлтым вердиктом с единственной находкой Medium (в скоупе), остальное ТЗ принято. Автор ответил комментарием (2026-09-11T09:58:44Z), назвав ровно три правки текста ТЗ: переписан К2, добавлен AC2а, переформулирован риск 1. Код между раундами не менялся (см. выше) — делать полный повторный разбор нет предмета: дельта строго локальна (один контрактный пункт, один новый AC, одна строка риска), не является ребейзом, не меняет контракт поведения за пределами уже поднятого вопроса и не затрагивает новую подсистему. Разбор в этом раунде ограничен дельтой и всем, до чего она дотягивается: К2, АС2/АС2а как пара, риск 1 и их согласованность с остальным контрактом (К1, К5) и остальными AC (AC1, AC3-AC9), которые дельта не меняет текстуально, но с которыми новый текст обязан не конфликтовать.

Закрытие раунда r1

Находка r1 Чем закрыта Где это видно
Medium — второй триггер К2 (сдвиг) не имел ни ориентировочной константы, ни собственного AC; ни один из AC1-AC9 не мог покраснеть, если реализация вообще не построит сдвиговую ветку К2 переписан как два явных условия с названными константами-ориентирами (LIVE_VIEWBOX_REFRESH_MS ≈100 мс, LIVE_VIEWBOX_REFRESH_SHIFT ≈0.15) и объяснением, зачем нужен второй; добавлен отдельный AC2а (unit), который с подменёнными часами проверяет сдвиговый путь независимо от временного: кадр со смещением выше порога обязан переписать viewBox немедленно, хотя LIVE_VIEWBOX_REFRESH_MS ещё не истёк, а кадр ниже порога — не должен переписывать Тело issue #531, раздел ### Контракт, пункт К2 (два подпункта «по времени» / «по сдвигу», абзац «Оба порога — константы модуля»); раздел ### AC, новый пункт AC2а
Low — обязательные разделы §7.1 присутствуют по содержанию, но не оформлены отдельными заголовками Снято ревьюером r1 без правки, автор текст не трогал (подтверждено комментарием «Low ... снят ревьюером без правки — текст не трогал») Не требует проверки — решение уже зафиксировано в SPEC-REVIEW-531-r1.md

Проверка не ограничилась чтением заявления автора: ниже — построчная сверка, что новый текст АС2а действительно ловит отсутствие сдвиговой ветки, а не просто существует.

АС2а умеет покраснеть. Если реализация не построит путь «накопленный сдвиг → досрочная перезапись» и оставит только временной бюджет — кадр со смещением выше LIVE_VIEWBOX_REFRESH_SHIFT, но с ещё не истёкшим LIVE_VIEWBOX_REFRESH_MS, при отсутствующей сдвиговой ветке не перепишет viewBox; AC2а прямо требует, чтобы он его переписал — assertion провалится. Симметрично: если реализация триггерит по сдвигу слишком рано (например, использует долю от неверной оси или не выполняет сброс накопленного смещения после перезаписи), негативная часть AC2а («кадр со смещением ниже порога — не переписывает») ловит и это. Это ровно тот сценарий, который в r1 не мог провалиться ни на одном из AC1-AC9 — пробел закрыт предметно, а не декларативно.

Согласованность с остальным контрактом не нарушена. К1 («каждый кадр — это только трансформ») и новое К2 не конфликтуют: кадр, на котором истёк один из двух бюджетов (временной или сдвиговый), — явно описанное исключение, а не нарушение К1, и после него «трансформ этих узлов возвращается в единицу в том же кадре» для обоих путей одинаково. АС2 (временной путь) и АС2а (сдвиговый путь) размечены как независимые сценарии и не пересекаются: АС2 говорит «по истечении бюджета», АС2а — «пока временной бюджет ещё не истёк». Риск 1 («пустая полоса на набегающем крае») теперь корректно ссылается на «оба порога К2» вместо одного, и вывод риска («пороги — константы модуля, их достаточно уменьшить») остаётся верным для обоих. AC5 (смок, суммарный счётчик перезаписей за 20 кадров) не переписан и не должен был: у него по-прежнему нет обязанности различать триггер — это ровно то, для чего существует АС2а. AC8 (таблица мутантов на К1/К4) не получил новой строки под сдвиговый триггер; это не пробел этого раунда — §2.7 (таблица «AC · чем доказан · чем краснеет») требование к код-ревью для защитных AC, а не к тексту спецификации, и АС2а сам по себе уже задаёт проверяемый негативный сценарий текстом.

Унаследовано из r1

Без повторной проверки в этом раунде приняты все выводы docs/reviews/SPEC-REVIEW-531-r1.md (материал: тело issue #531 на dev af2081cb), поскольку продуктовый код и остальной текст ТЗ, от которых эти выводы зависят, между раундами не менялись (подтверждено пустым git diff выше):

  • продуктовая рамка и выбор полного трека (docs/SCOPE.md, J1; критерий §5);
  • построчная сверка технических утверждений с src/live-viewport.ts, src/live-interaction-runtime.ts, src/houseplan-card.ts (paintLiveViewport пишет viewBox безусловно; isIdentityLiveLayerProjection уже существует у трансформа и отсутствует у viewBox; _floorView(view) === view в неизометрическом режиме — факт, не приближение; теги data-hp-live-viewbox/data-hp-live-layer существуют и используются как описано, включая изометрическую ветку);
  • проверяемость AC1, AC3, AC4, AC6, AC9 и их привязка к существующей инфраструктуре (test/live-viewport.test.mjs, scripts/mutation-gate.mjs, docs/ARCHITECTURE.md:1908);
  • честность разделения «AC внутри репозитория доказывают механизм» / «приговор по скорости — профиль владельца» (AC7 golden, раздел «Приёмка по скорости»);
  • риски 2-4, откат, touch-вывод («единственная точка входа _liveVp(), Pointer Events унифицируют мышь и тач — отдельного контракта не требуется»);
  • статус трёх «Принятых технических предположений» как действительно технических, не подменяющих продуктовое решение;
  • Low-находка о неформальной структуре разделов §7.1 — снята r1, автор текст, к которому она относится, не менял.

Находки

Нет. Единственная находка r1 (Medium) закрыта по существу — новый текст не просто добавляет константу, а даёт конкретный, способный провалиться сценарий для триггера, который раньше мог остаться нереализованным незамеченно. Новых находок дельта не вносит: правка локальна, не противоречит соседним пунктам контракта и не расширяет скоуп.

Чего не проверял

  • Гейты npx tsc --noEmit/npm test/npm run build/node scripts/check-docs.mjs не запускались — в материале этого раунда нет изменений класса A/B/D (диапазон origin/dev..HEAD пуст, src/** не менялся), прогонять их значило бы проверять пустое множество; та же логика, что в r1.
  • Реализуемость числовых ориентиров LIVE_VIEWBOX_REFRESH_MS≈100 мс и LIVE_VIEWBOX_REFRESH_SHIFT≈0.15 на живом железе владельца — по тексту ТЗ («Приёмка по скорости — отдельно и не здесь») это предмет профиля на этапе код-ревью/пре-релиза, не текста спецификации; унаследовано из r1 без повторной оценки.
  • Изометрический путь и поведение при одновременном зуме и панораме — унаследовано из r1 («детальная проверка изо-пути остаётся код-ревью по факту диффа»), дельта этого раунда К6 и зум не касается.

Вердикт

Зелёный · заход r2/4 · High: 0 · Medium: 0.

Единственная находка r1 закрыта предметно: К2 теперь называет константу для обоих триггеров перезаписи viewBox, и новый AC2а даёт сценарий, который красится именно на отсутствии сдвиговой ветки (проверено построчно выше, а не принято на слово автора). Согласованность нового текста с остальным контрактом (К1, К5, AC2, AC5, риск 1) проверена и дефектов не выявила. Код между раундами не менялся, поэтому весь остальной корпус выводов r1 наследуется без повторной проверки (раздел «Унаследовано из r1»).

Следующий статус — «Готово к разработке» (S5-ready).


Материал раунда

  • Ветка: dev, коммит b4a16ad7043d — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
  • Дерево материала: 9ac2a0132e8bb5d8db8eaab5fa14e1a714063caf
    git log --all --format='%H %T' | grep 9ac2a0132e8b
    
  • Тело issue: 89e75138a50434ac52f42cef606d8af741a8ae3b022dba382c4b62c1f4887e8a
  • Вердикт конвейера: green · High 0