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

194 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Ревью ТЗ — 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-хелпера — оба явно вынесены в блок «принято
предположительно, поменять свободно» и не являются предметом этого ревью.
## Вердикт
Зелёный. ТЗ готово к разработке.