Files
houseplan-card/docs/reviews/SPEC-REVIEW-20-r1.md
T
2026-08-28 22:31:02 +03:00

16 KiB
Raw Blame History

Ревью ТЗ — issue #20, заход r1

  • Issue: https://github.com/Matysh/houseplan-card/issues/20
  • ТЗ: docs/specs/020-glow-open-door-spill.md (коммит 962b1d0d, ветка issue/20-glow-open-door-spill, единственный коммит поверх origin/dev)
  • Трек: обычный (владелец явно снял small 2026-08-15 и подтвердил «лёгкий трек: нет» повторно 2026-08-28 — меняется горячий geometry/cache path и требуется performance proof)
  • Заход: r1 · блокирующих циклов израсходовано 0 из 4
  • Вердикт: зелёный · High: 0 · Medium: 0

Скоуп ревью

Проверялось ТЗ docs/specs/020-glow-open-door-spill.md как артефакт этапа S4-spec-review: обязательные разделы §7.1 PROCESS.md, однозначность и доказуемость AC1…AC10, соответствие docs/SCOPE.md, канонической модели docs/LIGHT.md и терминологии docs/USER-GUIDE.ru.md, а также независимая проверка каждого фактического утверждения ТЗ о текущем коде (не пересказ автора) — ТЗ описывает конкретные функции, кэш-ключи и геометрические типы, и первый вопрос ревью к такому тексту: существуют ли они там, где сказано, и делают ли то, что сказано. Продуктового кода по #20 нет (ветка содержит только правку ТЗ), поэтому гейты §8 к этому заходу неприменимы.

История issue: тело 2026-08-09 описывало старую (уже не существующую) модель интервалов-occluder; комментарий владельца 2026-08-11 актуализировал механику под пост-#71 модель полигона видимости; комментарий 2026-08-15 зафиксировал P3/feature/обычный трек и закрыл продуктовые вопросы («Вопросы: нет — поведение проёма без contact entity и fallback уже определены»); комментарий 2026-08-28 подтвердил взятие в работу и текущую редакцию ТЗ. Предыдущего цикла ревью ТЗ на этом issue не было — это первый заход, раздел «Унаследовано из r0» не применяется.

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

  1. Прочитаны docs/SCOPE.md, AGENTS.md, PROCESS.md (§2.3–2.10, §7.1, §7.2) целиком.
  2. Прочитано тело issue #20 и все четыре комментария владельца.
  3. Прочитан файл ТЗ 020-glow-open-door-spill.md целиком (224 строки).
  4. Прочитан канонический docs/LIGHT.md целиком — источник истины для модели света, на которую ТЗ явно ссылается.
  5. Проверена терминология в docs/USER-GUIDE.ru.md (Glow, ворота как аналог двери, «стены не пропускают Glow») — используемые в ТЗ слова не изобретены, они те же, что видит пользователь в интерфейсе.
  6. Независимо сверены с кодом все технические утверждения ТЗ, которые могли бы оказаться недоказанной догадкой, выданной за факт:
    • _lightBarriers() (src/houseplan-card.ts:10261-10392) — подтверждена фильтрация passages через isInteriorLightOpeningType (allowlist door | gate | passage), проверка пола по обе стороны (onFloor), разделение контурных вырезов (roomPassages/cuts) и партиций (_partitionOpeningCuts → PartitionOpeningCut), кэш-ключ contentFingerprint([raw, cellCm, gridPitch]) — сейчас не содержит состояние проёмов, что и есть повод для задачи;
    • openingAmount() (src/logic.ts:316-324) — подтверждён текущий бинарный контракт (0/1, fallback 1 для двери/ворот без датчика, unavailable/unknown не меняются invert) — ровно то, что таблица ТЗ §"Контракт поведения / 1" описывает как сохраняемый инвариант для известного/fallback случая; расширение под current_position cover — заявленная новая работа, не выдаётся за существующую;
    • _openingAmt()/OpeningVisibleSpec.amount (src/houseplan-card.ts: 12303-12309, src/render/opening-symbol.ts:8-61) — подтверждено, что символ проёма уже использует единое дробное amount в [0,1] (Math.max(0, Math.min(1, spec.amount))), то есть претензия ТЗ «один коэффициент для символа и Glow» технически реализуема без переделки символа — расширяется только источник числа;
    • PartitionOpeningCut (src/physical-geometry.ts:145-186) — подтверждён генерический сегмент {hostId, a, b, depth}, не привязанный к полной длине проёма — масштабирование a/b вокруг центра для частичного выреза, которое требует ТЗ, архитектурно естественно;
    • _roomWallOpeningInputs() (src/houseplan-card.ts:7494-7505, geometryRoomOpeningInputs) отдаёт {x, y, angle, length} на проём — подтверждено, что вырез строится из length вокруг центра (houseplan-card.ts:10310-10314), то есть length * amount с тем же центром/осью — не выдумка, а прямое следствие существующей формулы;
    • _contactCandidates() (src/houseplan-editor-runtime.ts:6379-6394) — подтверждено, что cover-домен уже допустим как opening.contact для дверных device_class (door, garage_door, garage, opening, window) — «доступный cover» в контракте ТЗ не новая возможность привязки, а новое использование уже существующей;
    • lruWrite(this._lightBarrierPool, cacheKey, entry, 8) и lruWrite(this._glowClipCache, clipKey, geometry, 256) (houseplan-card.ts:10389, 10506) — подтверждены названные в ТЗ границы LRU;
    • demo/smoke_glow.mjs, demo/fixtures/large-house.mjs, demo/benchmark_glow.mjs — подтверждено существование large-house-фикстуры и Glow-бенчмарка, на которые опирается AC9, ничего вымышленного.
  7. Проверено соответствие docs/SCOPE.md: владелец уже классифицировал задачу как «пространственная правдивость света» (комментарий 2026-08-15) — это часть J1 («живой пространственный обзор») и общей заявки миссии «live, tappable map»; ревью не переоткрывает уже принятое владельцем scope-решение.
  8. Проверены незакрытые продуктовые вопросы: их нет — владелец прямо подтвердил в комментарии 2026-08-15, что поведение без contact entity и fallback уже определено; в ТЗ нет ни одного утверждения о видимом поведении, помеченного как решённое, но не подтверждённого ни одним документом или существующим кодом.
  9. Код не запускался, гейты §8 не прогонялись — на этапе ревью ТЗ продуктового кода нет (см. «Скоуп ревью» выше).

Проверка §7.1 — обязательные разделы

Все присутствуют и содержательны: сценарий (персона/поверхность/момент) · что человек увидит до/после (одна фраза, без терминов реализации, кроме слова «Glow», которое само является интерфейсным термином из USER-GUIDE.ru.md, а не внутренним) · проблема · скоуп и не-скоуп · контракт поведения · UX · модель данных и миграция · i18n · AC1…AC10 с указанным способом доказательства (unit/smoke/golden/CI-perf) · план автотестов · риски и меры · откат · release-артефакты · блок «принято предположительно».

Блок «принято предположительно» (§218-223 ТЗ) содержит только технические решения (форма и файл чистого aperture-хелпера, сериализация signature, механика частичного PartitionOpeningCut, разбиение smoke/golden файлов) — ни одно из них не является продуктовым вопросом, спрятанным под видом допущения.

Проверка AC

Все десять AC пронумерованы, формулируют конкретное наблюдаемое поведение (или измеримый контракт кэша/perf) и называют способ доказательства:

  • AC1, AC2 — closed/open переход, unit геометрии + browser smoke с переключением состояния fake hass;
  • AC3 — частичное открытие через cover.current_position, unit + smoke по пикселям;
  • AC4 — матрица invert на известных/fallback состояниях, unit;
  • AC5 — классификатор типов (door/gate/passage прозрачны, window/наружная дверь/неизвестный тип непрозрачны), unit + smoke;
  • AC6 — паритет контурной стены и независимой перегородки, geometry unit + smoke fixture;
  • AC7 — fail-dark источника внутри закрытого проёма, source-guard unit/smoke;
  • AC8 — контракт кэша (переиспользование при посторонней сигнатуре, новый ключ при смене amount, bounded LRU), unit;
  • AC9 — perf-бюджет на large-house fixture, exact-SHA CI performance smoke перед бетой (согласовано с AGENTS.md: performance/golden — предрелизный гейт, а не гейт этой стадии);
  • AC10 — golden-сцена closed/open/50%, reviewed Linux golden-артефакт.

Все десять привязаны к реально существующим точкам расширения кода (см. п.6 выше), ни один не описывает несуществующий API как готовый.

Находки

Не найдено ни одной High- или Medium-находки. ТЗ не содержит утверждений о поведении, которых нет ни в docs/LIGHT.md, ни в текущем коде и которые не помечены как допущение; открытых продуктовых вопросов нет — они закрыты владельцем заранее.

L1 (Low, снимается без правки) — влияние на touch не названо отдельной строкой

DoR-чеклист (PROCESS.md §2.5) требует явно названного влияния на touch по docs/TOUCH-SUPPORT.md. В самом ТЗ такой отдельной строки нет. Снимаю без правки: раздел «УХ» ТЗ прямо утверждает «новых контролов и сообщений нет» — изменение целиком в рендеринге Glow в View/kiosk, без нового взаимодействия, а docs/TOUCH-SUPPORT.md требует паритета именно для интерактивных путей View, которых здесь не появляется. Рендер одинаков на любом указывающем устройстве; отдельно фиксировать «влияние: нет» было бы формальностью, а не содержательной проверкой. Если автор всё же добавит эту строку явно в ТЗ — это не будет считаться повторным циклом ревью.

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

  • все причинно-следственные утверждения ТЗ о текущей модели (_lightBarriers, openingAmount, PartitionOpeningCut, LRU-границы, cover-контакты, large-house-фикстура) подтверждены чтением кода, а не поверены на слово;
  • контракт таблицы «Один коэффициент открытия» не противоречит текущему поведению openingAmount() для известных/fallback случаев — расширяет его, не переопределяя уже проверенный инвариант;
  • не-скоуп корректно исключает наружный свет, tunnel fill, автоматическое управление дверью и смену конфигурационной схемы — ни один пункт не расширяет заявленный скоуп «мимоходом»;
  • release-артефакты называют актуализацию docs/LIGHT.md, что необходимо: канонический документ сейчас не описывает частичную апертуру и обязан получить это описание в том же изменении;
  • открытых продуктовых вопросов нет, что подтверждено собственным комментарием владельца, а не заявлением автора ТЗ.

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

  • Не запускал npm run typecheck/npm test/npm run build — продуктового кода в ветке нет, применять их не к чему на этой стадии.
  • Не проверял производительность фактическим прогоном benchmark_glow.mjs — AC9 сам относит это доказательство к предрелизному exact-SHA CI, а не к этому циклу.
  • Не проверял golden — сцена ещё не существует (AC10, план автотестов п.4), проверять нечего до реализации.
  • Не оценивал точную формулу сериализации openingStateSignature и место файла aperture-хелпера — оба явно вынесены в блок «принято предположительно, поменять свободно» и не являются предметом этого ревью.

Вердикт

Зелёный. ТЗ готово к разработке.