Files
houseplan-card/docs/reviews/SPEC-REVIEW-431-r1.md
T
Codex d4dd027b0a build: prepare v1.71.0-beta.2 candidate
Issue: #426
Issue: #427
Issue: #428
Issue: #431
Issue: #432
Issue: #434
User-Visible: no
2026-09-03 15:23:40 +03:00

15 KiB
Raw Blame History

SPEC-REVIEW #431 · r1

Issue: #431 — kind:'image' выпал из канонизации координат. Документ ТЗ: docs/specs/431-image-coordinate-canonicalization.md Материал: коммит 260af7bfd200bb40beb2323af2ad5232e2686325 (docs(spec): define image coordinate canonicalization, Issue: #431 · User-Visible: no), совпадает с HEAD. Трек: полный (не small) — причина названа автором в S2-analysis и в ТЗ и подтверждена ниже.

Скоуп ревью

Первый заход. Проверено: соответствие продуктовой рамке docs/SCOPE.md, полнота разделов §7.1, однозначность и доказуемость AC1–AC8, отсутствие непомеченных догадок, корректность трек-классификации (полный vs small), трассируемость issue ↔ ТЗ.

Как проверялось

Ревью читало ТЗ состязательно, без пояснений автора, и сверяло каждое фактическое утверждение с текущим деревом (не с описанием ТЗ):

  • прочитаны docs/SCOPE.md, PROCESS.md (§1–§10.4), AGENTS.md целиком;
  • прочитан текст issue #431 и все три комментария (аналитика, занятие, «ТЗ готово»);
  • сверены src/coordinate-canonicalization.ts (обе точки: visitLatticeCoordinates строка 158 и canonicalizeConfigGeometryInPlace строка 338) и custom_components/houseplan/coordinate_canonicalization.py строка 153 — оба действительно перечисляют ("rect", "ellipse", "furniture") без image, как заявлено в issue и ТЗ;
  • сверен src/editors/decor/types.ts — DecorImage extends DecorBoxBase с полями x/y/w/h/angle подтверждён, DecorKind содержит 'image';
  • сверена test/fixtures/coordinate-canonicalization.json и test/coordinate-canonicalization.test.mjs — фикстура содержит line/rect/ ellipse/text/furniture, image действительно отсутствует;
  • проверено, что custom_components/houseplan/validation.py:1909 (CONFIG_SCHEMA) вызывает тот же canonicalize_config_geometry внутри vol.All(...), то есть Python не имеет отдельной ветки для схемы — правка одной функции закрывает оба пути, как утверждает AC3;
  • проверено, что все вызовы canonicalizeConfigGeometry(InPlace) / latticeCanonicalizationReport во фронтенде (houseplan-card.ts, houseplan-editor-runtime.ts, plan-optimizer.ts, wall-segment-model.ts) идут через единый модуль — второй путь канонизации, которого ТЗ могло бы не заметить, отсутствует;
  • проверено, что перечисления rect/ellipse/furniture в houseplan-editor-runtime.ts и houseplan-card.ts относятся к UI-логике редактора (заливка, диалоги), не к канонизации, и там image уже присутствует, где это нужно — подтверждает, что ТЗ верно провело границу не-скоупа;
  • проверено, что tests_backend/test_coordinate_canonicalization.py требует pytest.importorskip("homeassistant"), то есть локально без HA-харнесса тихо скипается — подтверждает, что заявленный в AC4 backend-mutation-gate witness оправдан правилом §2.7 («дорогой гейт, ревьюер не воспроизведёт отрицательный прогон второй раз»), а не избыточная предосторожность;
  • проверено наличие существующих записей coordinate_canonicalization.py / coordinate-canonicalization.test.mjs в scripts/mutation-gate.mjs (строки 2276–2430) — механизм добавления нового witness-мутанта в этот файл уже существует и используется для смежных контрактов, расширение реалистично;
  • сверен docs/CONFIG-COMPATIBILITY.md (раздел «Custom decor images and export v2 (#51)») — image там не упомянут как часть box-контракта канонизации, что подтверждает необходимость правки AC7;
  • сверена трассируемость: коммит 260af7bf правит и сам файл ТЗ, и docs/specs/README.md (новая строка со ссылкой на issue и файл) в одном коммите с верными трейлерами.

Гейты не гонялись: класса A/B изменений на этом SHA нет (только docs/specs/**, класс C), а полный typecheck/test/build уже зелёный на этом же SHA (https://github.com/Matysh/houseplan-card/actions/runs/33732448117). Продуктового кода к ревью нет — оценивать нечего гейтами.

Проверка трек-классификации

Автор в S2-analysis назвал критерий §5, который задача не проходит: «одна поверхность (один диалог, один модуль, один эндпоинт)» — нарушен, потому что исправление обязано синхронно и доказуемо менять TypeScript-модуль и Python-зеркало. Это соответствует факту: правка действительно охватывает два независимых рантайма на разных языках с раздельными тестовыми наборами (test/ и tests_backend/) плюс scripts/mutation-gate.mjs. Классификация «полный трек» обоснована корректно, файл docs/specs/NN-*.md создан, как и требуется вне small.

Проверка §7.1

Все обязательные разделы присутствуют по содержанию (частично объединены заголовками, что не является нарушением — угроза объёма шаблона не в счёт): сценарий; что человек увидит до/после; проблема («Подтверждённая причина»); скоуп/не-скоуп; контракт поведения; UX/touch/i18n/производительность; модель данных и миграция («Совместимость и миграция»); AC1–AC8 с методом доказательства у каждого; план автотестов, включая таблицу защитных свидетелей в формате §2.7 (три столбца: AC · чем доказан · чем обязан краснеть) — авторское решение оформить её уже на этапе ТЗ облегчает будущее код-ревью и не требуется, но полезно; риски; откат; release-артефакты.

Проверка AC на однозначность и доказуемость

AC1–AC8 пронумерованы, у каждого указан способ доказательства (unit/backend/mutation/review-code/gates), формулировки конкретны (какие именно поля, какие функции, какой ожидаемый результат). AC4 и AC5 явно требуют прогона каждого вида через контракт, а не сравнения списков строк — учтён риск №4, названный автором самим же («тест проверяет список, но не поведение»). AC6 явно фиксирует границы не-скоупа (формула, пороги, версии, writer inventory, UI, i18n не меняются) и требует зелёности регрессионных наборов #224/#248/#291 — это защищает именно тот класс регрессии, которого стоит опасаться при трогании общего модуля.

Проверка на непомеченные догадки

Утверждения о поведении (девять знаков после запятой для angle, точка отсечения lattice-шума, что latticeCanonicalizationReport считает near-node как canonicalized, что CONFIG_SCHEMA пропускает конфиг через canonicalize_config_ geometry) все сверены с действующим кодом и не являются догадками — это описание существующего контракта, который расширяется на новый вид, а не изобретается заново.

Раздел «Принятые предположения» корректно маркирует то, что реально является техническим решением автора (расположение единого каталога, трактовка flip_h/ flip_v, независимость fixture от рантайма). Единственный пункт на грани продукт/техника — квалификация коммита как User-Visible: yes при отсутствии видимого визуального кадра. Оценка: это не продуктовый вопрос из списка §7.1 («что человек видит или делает», «объём видимого изменения в issue») — объём изменения уже зафиксирован issue целиком, а User-Visible лишь описывает, что фикс меняет наблюдаемое поведение конфига (частота ревизий/диффов), что описано в таблице «Что человек увидит до и после». Решение разумное и не создаёт риска даже если бы было неверным (худший случай — лишняя запись в changelog, не блокирующая задачу). Эскалации не требует.

Находки

Нет ни High, ни Medium, ни Low. Задача демонстрирует образцовую точность: каждое фактическое утверждение о коде проверяется прямым чтением исходников, границы скоупа проведены по реальным точкам вызова, а не по предположению, риски названы автором заранее и закрыты соответствующими AC.

Что проверено и корректно

  • Соответствие docs/SCOPE.md: попадает в J6 («Keep the plan true as the home evolves») — устранение шумовых диффов персистентной геометрии.
  • Классификация полного трека обоснована названным критерием §5.
  • Все §7.1-разделы присутствуют по содержанию.
  • AC1–AC8 однозначны, каждому назначен метод доказательства.
  • Защитные AC (AC4) уже содержат таблицу «чем доказан / чем краснеет» с корректным выбором mutation-gate именно там, где гейт дорогой (backend требует HA).
  • Фактические утверждения о коде (номера строк, сигнатуры функций, поведение CONFIG_SCHEMA, состав фикстуры) подтверждены чтением текущего дерева.
  • Трассируемость issue ↔ ТЗ ↔ docs/specs/README.md в одном коммите с верными трейлерами (Issue: #431 · User-Visible: no, коммит только класса C).
  • Продуктовых вопросов владельцу нет, и это верно: контракт box-геометрии уже зафиксирован #223/#224/#291/#51, добавление image — не новое решение, а возврат к уже принятому контракту.

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

  • Гейты typecheck/test/build/check-docs не перегонялись самостоятельно: на этом SHA нет продуктового кода (только docs/specs/**), а зелёный Validate на этом же SHA уже подтверждён ссылкой в задании ревью.
  • Реализация (код, тесты, mutation-gate witness) не существует и не проверялась — предмет этого этапа только ТЗ.
  • Не проверялось поведение редактора/рендера изображений в браузере — вне скоупа задачи и вне этапа spec.

Вердикт

Зелёный. ТЗ выполнимо, каждый AC проверяем и снабжён способом доказательства, догадок под видом фактов не найдено, трек-классификация обоснована.


Материал раунда: SHA 260af7bfd200bb40beb2323af2ad5232e2686325, дерево — рабочая копия на момент ревью, blob ТЗ — docs/specs/431-image-coordinate-canonicalization.md в этом же коммите.


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

  • Ветка: issue/431-image-coordinate-canonicalization, коммит 260af7bfd200 — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
  • Дерево материала: 00fc18d8eda6f680117f99866f8e4063cdbb200c
    git log --all --format='%H %T' | grep 00fc18d8eda6
    
  • ТЗ docs/specs/431-image-coordinate-canonicalization.md, блоб 664b75d910be1fcf8ddf2034daec437b2c05430f
    git log --all --find-object=664b75d910be1fcf8ddf2034daec437b2c05430f -- docs/specs/431-image-coordinate-canonicalization.md