# CODE-REVIEW-560-r1 Issue: #560 «Корпус геометрий, household-сценарии и аудит доступности View» Материал: `db7eef530635b699a72c3cf978a7df79db99fcbd`, ветка `issue/560-quality-field-corpus` на `dev` (`a03ccd65`), один коммит. Заход: r1 · блокирующих циклов ревью 0 из 4 (лимит для инфраструктурного/полного трека — 4) ## Скоуп Задача — прямое поручение владельца по оставшемуся пункту независимого аудита (12.09.2026): усилить доказательства View household-сценариями и корпусом пользовательских геометрий. Инфраструктурная постановка (`infra`, без продуктовых `S*`-статусов до `S7-code-review`), явно **research/tests-only**: диффу запрещено трогать `src/**` и `custom_components/**`, а находки — заводиться отдельными issue, а не чиниться здесь. `git diff origin/dev...HEAD --stat` подтверждает границу: только `demo/**`, `test/**`, `scripts/mutation-registry.mjs`, `docs/QUALITY-560.md` — класс B/C, ни одного файла класса A. Трейлеры коммита: `Issue: #560`, `User-Visible: no` — корректны, продуктового поведения нет. Три направления приёмки (SCOPE J1/J2/J3/J6): 1. household-сценарии View на двух ширинах карточки; 2. аудит доступности текущего View; 3. обезличенный geometry corpus (import → Optimize → Optimize → Resize → save/reload → export) с численными оракулами. ## Как проверялось Ревью независимое: сессия без контекста реализации, материал не редактировался. Дешёвые гейты (`tsc`, `npm test`, `npm run build`) уже подтверждены зелёным прогоном Validate на этом самом SHA — перепрогонять не стал, а сверил сам факт: | гейт | результат | |---|---| | Validate (CI) на `db7eef53` | `gh run view 34773796018` → `conclusion: success`, `headSha: db7eef53...` — совпадает | Что прогнал сам (соразмерно диффу и AC, не входит в «дешёвый» набор, зафиксированный Validate): | гейт | команда | результат | |---|---|---| | build (нужен как база для смоков) | `npm run build && npm run bundle:sync` | зелёный, дерево бандла не изменилось (`git status` чист после) | | unit-тесты | `npm test` | `2679` тестов, `2678` pass, `0` fail, `1` skip — совпадает с заявленным «2678 / 0 / 1 skip (+35)» | | новый браузерный смок 1 | `node demo/smoke_household_journeys.mjs` | `OK`, все числа (J4 15 остановок Tab, F1 390px владельцы `dense2,dense3,dense4,dense5,dense5`, J7 780px владельцы `dense1..dense5`) совпадают с `docs/QUALITY-560.md` | | новый браузерный смок 2 | `node demo/smoke_geometry_corpus.mjs` | `OK`, числа (3 комнаты, толщины `20,20,20,20,20,20,20,22,33,33` до/после ресайза, 2 комнаты+1 проём для c4) совпадают с отчётом | | mutation-gate — 4 новых мутанта, по одному | `node scripts/mutation-gate.mjs --id=` × 4 | все 4: «поймано 1 из 1» (см. таблицу ниже) | | mutation-gate anchors | `node scripts/mutation-gate.mjs --check` | без нарушений | | process-gate | `node scripts/process-gate.mjs --issues` | «гейт пройден», 1 WARN (см. находку Low ниже) | | check-docs | `node scripts/check-docs.mjs` | passed (диффу не требовался — `src/**` не тронут) | | smoke-select | `node scripts/smoke-select.mjs --base origin/dev --head HEAD` | «исполняемого frontend-диффа нет, browser-smoke этим диффом не выбираются» — ожидаемо для инфра-трека без `src/**` | | model-invariants CLI (сверка численных оракулов вручную) | `node scripts/model-invariants.mjs --config ... --layout ...` на `c6-stale-layout` | «Нарушений: 2» — `references/layout_space` × 2, совпадает с `expectedViolations` теста и находкой #566 | | приватность фикстур | `grep` по `test/fixtures/560-corpus/*.json` на `sensor.\|light.\|binary_sensor.\|climate.\|lock.` | ничего не найдено; маркеры в геометрических фикстурах — пустые массивы | Не прогонял и почему: - `golden:verify`, `performance_smoke`, `python -m pytest tests_backend` — diff не трогает `src/**` (рендер и стили не менялись) и не трогает `custom_components/**/*.py`; ни один AC не требует визуального или бэкенд-гейта. - Полный набор `demo/smoke_*.mjs` — `smoke-select` прямо сообщил, что выбирать нечего (frontend не менялся); два новых смока прогнаны напрямую целиком. ## Находки ### Low — `process-gate` даёт 1 предупреждение, а хендофф заявляет «предупреждений 0» `node scripts/process-gate.mjs --issues` на этом дереве печатает: ``` WARN п.8 статус issue - инфраструктурный диапазон (#562): файлов класса A нет, статусная метка не требуется до S7-code-review гейт пройден, предупреждений 1 ``` Это ожидаемое, безопасное предупреждение — оно печатается всегда для инфраструктурного диапазона по дизайну (`scripts/process-gate.mjs:806-813`, комментарий «пропуск обязан быть виден»), гейт всё равно зелёный. Расхождение чисто в тексте хендоффа («предупреждений 0» вместо факта «1»), не в существе проверки. Не блокирует; правится или снимается автором с примечанием. Третий столбец («чем краснеет») для этой находки не нужен — она не о защите, а о точности отчётной цифры. ## Что проверено и корректно - **Границы задачи соблюдены.** Ни одного файла класса A в диффе; все три находки уровня High/Medium (F1 «390px — соседний маркер», F2 «контраст подписей 2,01:1», F3 «активная вкладка без ARIA-состояния») и Low (F4, F5, F6) заведены отдельными issue со ссылкой на #560 — проверил напрямую: `#564` (High, bug, P1, S1-new), `#565` (Medium+Low, bug, P2, S1-new), `#566` (Low, tech-debt, P3, S1-new) существуют, открыты, корректно размечены. Ничего не оставлено как TODO внутри документа ревью/отчёта. - **Приватность данных.** Реальный план владельца (5 пространств/37 комнат/121 запись толщины и т.д.) в репозиторий не попал — фикстуры `test/fixtures/560-corpus/*.json` синтетические, воспроизводят условия числами; маркеры пустые, ссылок на реальные HA-сущности нет (проверено grep). - **Каждый AC приёмки закрыт и доказан исполнением, не чтением:** - «персона/вход/действие/независимый oracle» — семь J-путей в `demo/smoke_household_journeys.mjs` прогнаны, оракулы независимые (вызов `light.turn_off`, `aria-label`, `data-state`, а не факт наличия класса) — подтверждено запуском, числа совпали. - «geometry corpus не принимает рендер как эталон» — оракулы в `test/geometry-corpus.test.mjs` численные (инварианты, immutability Optimize, фикс-пойнт #477, сохранность записей толщины, независимый пересчёт `wallKey`); браузерная половина проверяет только присутствие узлов и попадание в `viewBox`, не пиксели — прочитано и прогнано. - **Тест умеет падать.** Для двух product-facing защит (клавиатурная доступность маркера, вызов действия по Enter/Space) и двух свойств самого корпуса (фикстура несёт условие, `changed` не врёт) прогнаны названные мутанты — все 4 «поймано 1 из 1» (перепроверено мной лично, не с чужих слов). - «bounded corpus, без бесконтрольного роста» — 6 фикстур × (свой тест условия + 3 теста цепочки) + 2 сквозных теста = 26, как заявлено; синтетика (`c3-x-junction`) прямо помечена как таковая и в тесте, и в отчёте. - «итог отделяет bugs от гипотез» — раздел 6 `docs/QUALITY-560.md` называет U1–U3 гипотезами именно потому, что без людей (screen reader, color-blindness sim, доброволец) не проверяются; это не притворство решением, а честно обозначенная граница. - **Числа отчёта воспроизводимы**, а не переписаны на веру: гоняя оба новых смока и `npm test` заново, получил те же цифры, что в `docs/QUALITY-560.md` (включая тонкие — 1,6 px запас на 780px, 15 остановок Tab, `rev`-независимые толщины). Ни одного «verified» без названной команды в материале нет. - **Единый источник числа.** Диф не вводит ни одной новой пользовательской величины (не продуктовый код); дублирования вида «превью против записи» не создаётся. ## Чего не проверял и почему (сверх раздела «как проверялось») - Не проверял вручную полевую установку владельца — по постановке задачи это read-only полевая часть текущего захода, она не воспроизводима вне сессии автора и с чужой машины не перепроверяется; профиль (числа) сверен на внутреннюю согласованность с корпусом, а не с самим домом. - Не гонял скринридер/цветовую симуляцию — U1–U3 прямо помечены как гипотезы, не как заявленные доказанные AC; требовать здесь исполнимый oracle было бы спором с самой постановкой задачи (research/tests-only, без людей в этом заходе). ## Вердикт Единственная находка — Low, редакционная неточность в тексте хендоффа («0» вместо фактических «1» предупреждения `process-gate`, само предупреждение ожидаемо и не является нарушением). High/Medium в материале нет. Задача решает заявленный сценарий (усиление evidence по трём направлениям аудита) без деградации соседнего поведения — продуктовый код не тронут вовсе. **Зелёный.** --- ## Материал раунда - Ветка: `issue/560-quality-field-corpus`, коммит `db7eef530635` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Дерево материала: `eea41e91476fced5276e10601e5d29ad1bd6642b` ``` git log --all --format='%H %T' | grep eea41e91476f ``` - Тело issue: `0ab01902457f91e2bbe866f790b19fb58567ef790403214e6886dc7df209ac70` - Вердикт конвейера: `green` · High 0