19 KiB
CODE-REVIEW-508-r2
Issue: #508 — «Сводная панель: в диалоге настроек не работает прокрутка — колесом мыши и touch на мобильных»
Материал: 6ac513caa09a8e583869879412aa3a0c67d04488 (рабочая копия уже на нём). Ветка приведена конвейером к
dev до ревью: e23d742c → 6ac513ca, поверх легло 1 коммит dev (несвязанный — docs: review document for #502).
Заход: r2 · блокирующих циклов израсходовано 0 из 4. Ребейз на ушедший вперёд dev формально делает
дерево другим (§7.2) → разбор полный, а не по дельте.
Почему вообще r2, если r1 был зелёным без находок
Код-ревью r1 (docs/reviews/CODE-REVIEW-508-r1.md, материал 768e1281) уже завершилось вердиктом
«зелёный, находок нет» с исчерпывающим личным прогоном гейтов, мутантов, смоков и подтверждением автора
на живом стенде HA. Сразу после публикации вердикта автор сообщил в issue: «Автоматическое ревью не
отработало» — статусная метка не переставилась, конвейер оставил задачу на месте. Затем конвейер
перебазировал ветку на успевший уйти вперёд dev (там landing получил несвязанный коммит с ревью-доком
для issue #502) и передал её на повторное ревью уже под новым SHA. Автор с момента r1 в код и ТЗ не
вносил ничего — это не возврат на правки, а техническое повторение ревью из-за сбоя механики метки плюс
ребейз. Поэтому раздела «находка → возврат → правка» в этом раунде по существу нет: проверка ниже —
подтверждение, что ребейз не изменил и не сломал ничего, а не разбор чьих-то правок.
Скоуп
Не изменился с r1: один функциональный коммит (e38beed7, экс-768e1281) — класс A (src/hp-dialog.ts,
src/summary-panel-editor.ts) + класс B (новый смок demo/smoke_summary_dialog_scroll.mjs, контрактный
юнит-тест test/hp-dialog-contract.test.mjs, два мутанта в scripts/mutation-gate.mjs) + класс C
(docs/ARCHITECTURE.md, оба CHANGELOG) + класс D (пересобранный бандл во всех копиях,
docs/images/screenshots.json — только фингерпринт). hp-dialog получает opt-in булев атрибут
flex-content (?flexcontent на ha-dialog, обе HA-ветки рендера); нативная <dialog>-ветка не тронута.
Диалог настроек сводной панели его объявляет — единственный из десяти вызывающих <hp-dialog>.
J1 (docs/SCOPE.md) — обзорная сводная панель входит в «show the whole home at a glance»; чистый
баг-фикс регресса после #505, скоуп не расширен, продукт не меняет договор.
Как проверялось (это не дельта — это независимая перепроверка «ничего не изменилось»)
Первый шаг — не поверить заявлению «ребейз ничего не тронул», а доказать его:
git diff 768e1281 e38beed7 --stat # r1-материал vs текущий фикс-коммит
Результат: единственная разница — файл docs/reviews/SPEC-REVIEW-502-r1.md (несвязанный коммит dev для
issue #502). Все файлы продукта — src/hp-dialog.ts, src/summary-panel-editor.ts,
test/hp-dialog-contract.test.mjs, docs/ARCHITECTURE.md, оба CHANGELOG, scripts/mutation-gate.mjs,
demo/smoke_summary_dialog_scroll.mjs, весь пересобранный бандл — побайтово идентичны материалу r1.
docs/images/screenshots.json проверен построчно (grep imageSha256 на диффе): изменились только
sourceFingerprint/sourceSha256-контекст, ни один imageSha256 не сдвинулся.
Это и определило объём: код доказанно тот же, что уже получил зелёный вердикт с личными прогонами гейтов,
мутантов и смоков (не только заявлением автора — заявление в r1 тоже было перепроверено исполнением). Все
выводы AC1–AC6 из r1 остаются в силе автоматически, потому что применяются к тому же байт-в-байт коду. Тем
не менее раунд объявлен «полным» (ребейз, §7.2), поэтому ниже — не просто ссылка на r1, а собственный
прогон части гейтов на текущем SHA 6ac513ca, чтобы исключить эффекты самого ребейза (окружение сборки,
конфликт слияния бандла и т. п.), а не только идентичность текста диффа.
Дешёвые гейты
Validate на 6ac513ca зелёный (дано в задаче ревью, https://github.com/Matysh/houseplan-card/actions/runs/34397342070)
— tsc, npm test (2436/2436), npm run build со сверкой бандла уже подтверждены конвейером на этом
самом SHA, повторно не гонял.
Прогнано лично на 6ac513ca (не на материале r1 — на текущем SHA)
| Гейт/смок | Результат |
|---|---|
node --test test/hp-dialog-contract.test.mjs (AC1 текстовая часть, AC4) |
3/3 pass |
node scripts/check-docs.mjs (диф трогает src/**) |
«Documentation checks passed (7 files, 12 external links)» — совпадает с числом из r1 |
node scripts/bundle-sync.mjs (пересборка + раскладка по трём местам: dist, custom_components/houseplan/frontend, demo/srv/assets) |
выполнено; git status --porcelain после — пусто (отслеживаемые копии не разошлись с коммитом) |
node demo/smoke_summary_dialog_scroll.mjs (AC1/AC2, прямое совпадение) |
OK |
node demo/smoke_summary_panel_polish.mjs (AC3, прямое совпадение — файл смока не менялся) |
OK |
node demo/smoke_dialog_modal_recovery.mjs (зарегистрированная связь: общий hp-dialog) |
OK |
node demo/smoke_esc_dialogs.mjs (зарегистрированная связь) |
OK |
node demo/smoke_dialog_footer_width.mjs (зарегистрированная связь) |
OK |
node scripts/mutation-gate.mjs --id=summary-dialog-drops-flex-content |
чистый прогон OK → мутация: «тест покраснел, как обязан» → поймано 1 из 1 |
node scripts/mutation-gate.mjs --id=hp-dialog-ignores-flex-content |
то же → поймано 1 из 1 |
node scripts/smoke-select.mjs --base origin/dev --head HEAD |
«НЕОПРЕДЕЛЁННОСТЬ» — 2 файла src/**, 0 символов на изменённых строках (тот же результат, что в r1); выбор смоков выше сделан вручную: прямое совпадение (диалог панели) + зарегистрированные связи (общий hp-dialog) |
grep -rn "<hp-dialog" src/ |
10 вызывающих (включая summary-panel-editor.ts); ровно список из test/hp-dialog-contract.test.mjs AC4, opt-in — один |
Изначально попытка запустить браузерные смоки провалилась ошибкой окружения
(Failed to fetch dynamically imported module: http://demo.local/..., page.waitForFunction timeout) —
это была не регрессия, а отсутствие локальной копии demo/srv/assets (она не хранится в репозитории,
scripts/bundle-sync.mjs: «копий две с половиной», рабочая копия стенда собирается заново). Тот же
таймаут воспроизводился на demo/smoke_summary_panel_polish.mjs, файл которого этот диф не трогает вовсе
— это подтвердило, что причина в окружении ревью-песочницы, а не в коде. После node scripts/bundle-sync.mjs (пересборка из уже собранного dist/) оба смока пошли зелёными.
Закрытие раунда r1
Код-ревью r1 не имело находок (High 0, Medium 0, Low 0) — блокирующих находок для закрытия нет. Раунд r2
открылся не как возврат на правки, а как техническое повторение из-за несработавшей автоматической
перестановки метки после зелёного вердикта r1, дополненное последующим ребейзом на ушедший вперёд dev
(конвейер, не автор). Автор кода/ТЗ с момента r1 не менял — независимо доказано выше диффом
768e1281..e38beed7.
| Находка r1 | Статус | Где видно |
|---|---|---|
| (нет находок) | — | docs/reviews/CODE-REVIEW-508-r1.md, раздел «Находки»: «Нет. High: 0, Medium: 0, Low: 0» |
Унаследовано из r1
Без повторного самостоятельного вывода, но с проверкой байт-в-байт идентичности кода (см. «Как
проверялось»), наследую из docs/reviews/CODE-REVIEW-508-r1.md (материал 768e1281f9119b12d018b416372984ff17eae62d,
дерево 1594677359b610e22fc5886db02f66bc3c943322):
- диагноз (scroll chaining обрывается на height-unbound
.summary-editorподha-dialog,overflow: auto+overscroll-behavior: contain) — независимо подтверждён автором на живом стенде HA 2026.9.1, не только в стабе смока; - личные прогоны
tsc,npm test(2437/2436 pass+1 skip),no-new-any,bundle:budgetна материале r1 — не переигрывал повторно, т. к. Validate CI зелёный на6ac513caпокрывает те же проверки на байт-в-байт идентичном коде; - вывод AC6 (i18n/модель/перф не задеты, трейлеры
Issue:/User-Visible: yesи оба CHANGELOG в одном коммите) — перепроверен построчно, см. «AC → доказательство» ниже, поэтому это скорее «переподтверждено», чем слепо унаследовано; - трассировку к спек-ревью (
SPEC-REVIEW-508-r1.mdжёлтый →SPEC-REVIEW-508-r2.mdзелёный на SHAf02af9330b17a37eea6c8086f4335cbbc7265d36, M1/M2 закрыты правкой тела issue) — код-ревью r1 её не переоткрывало, r2 тоже не переоткрывает: текст issue с тех пор не менялся.
AC → доказательство → чем краснеет (переподтверждено лично на 6ac513ca)
| AC | Доказано | Чем краснеет |
|---|---|---|
AC1 (HA-ветка: колесо крутит .summary-editor, шапка/футер неподвижны) |
demo/smoke_summary_dialog_scroll.mjs сценарий (a) — OK, лично |
оба мутанта, лично: «покраснел, как обязан» |
| AC2 (touch 390×844 крутит редактор; диалог ≤ вьюпорта; футер доступен) | сценарий (b) — OK, лично |
те же два мутанта |
| AC3 (нативная ветка не меняется) | smoke_summary_panel_polish — OK, лично; файл смока не в диффе |
не защитный AC |
AC4 (прочие 9 hp-dialog без flex-content) |
test/hp-dialog-contract.test.mjs — 3/3 pass, лично; grep по src/** — 10 вызывающих, 1 opt-in |
ассерт === 1 в тесте (in-memory проба r1 сохраняет силу — код теста не менялся) |
| AC5 (оба мутанта пойманы) | оба мутанта лично прогнаны — «поймано 1 из 1» каждый | это и есть доказательство |
AC6 (User-Visible: yes, оба changelog, i18n/модель/перф не задеты) |
git show --stat e38beed7: docs/CHANGELOG.md+docs/CHANGELOG.ru.md в том же коммите; git log -1 коммита содержит Issue: #508 и User-Visible: yes; ни один i18n/translations файл не в диффе; src/hp-dialog.ts diff — только проброс булева атрибута, новых обработчиков нет |
не защитный AC, доказано чтением |
Одно число — один источник
Диф не вводит и не дублирует ни одну видимую пользователю величину (площадь, значение, подпись): меняется
только внутренняя раскладка скролл-контейнера через булев атрибут. test/single-source-numbers.test.mjs
не затрагивается и не требуется для этой правки.
Что проверено и корректно
- Обе HA-ветки рендера (
describedByи без) несут?flexcontent=${this.flexContent}— строкиsrc/hp-dialog.ts:515,531, подтверждено и тестом, и мутантами лично. - Нативная
<dialog>-ветка не содержитflexcontent/связанных селекторов — регресс на неё исключён и тестом (smoke_summary_panel_polish), и построчным чтением. docs/TOUCH-SUPPORT.md:48–49называет «simple settings form» сводной панели гарантированной View-touch- поверхностью — включение touch в скоуп не расширение, а обязательное соответствие контракту.- Терминология CHANGELOG.ru.md («сводной панели», «настроек») совпадает с
docs/USER-GUIDE.ru.md:264(«Настройки сводной панели»). docs/images/screenshots.json: толькоsourceFingerprint/sourceSha256; все 11imageSha256идентичны — докс-скриншоты не изменились по существу.- Один коммит (
e38beed7), трейлерыIssue: #508иUser-Visible: yesна месте. - После
bundle-syncрабочая копия чиста (git status --porcelainпуст) — три копии бандла (dist,custom_components/houseplan/frontend,demo/srv/assets) согласованы с закоммиченным. - Ребейз сам по себе не внёс никакого продуктового изменения — доказано диффом, а не заявлено.
Находки
Нет. High: 0, Medium: 0, Low: 0.
Чего не проверял и почему
npm run golden:verify— атрибут opt-in,?flexcontent=в Lit убирает атрибут целиком приfalse, разметка прочихhp-dialogне меняется ни на байт; golden-сцен диалога сводной панели в репозитории нет (снято ещё вSPEC-REVIEW-508-r1.mdM1). Риск нулевой, решение то же, что в r1, переподтверждено тем же рассуждением на идентичном коде.python -m pytest tests_backend— диф не касаетсяcustom_components/houseplan/**/*.py.- Полная матрица смоков (237 шт.) и перф-профили — не названы в AC;
smoke-selectвернул «НЕОПРЕДЕЛЁННОСТЬ» (2 файлаsrc/**, 0 символов на изменённых строках, порог «широкого» — 47 смоков). Выбор сужен вручную до прямого совпадения (smoke_summary_dialog_scroll,smoke_summary_panel_polish) и зарегистрированных связей на общийhp-dialog(smoke_dialog_modal_recovery,smoke_esc_dialogs,smoke_dialog_footer_width) — все пять прогнаны лично, все зелёные. npm run invariants— диф не трогает геометрию/рёбра комнат/layout/marker.space/open_spans, гейт не применим.- Полный
npm test(все 2436 юнитов) — не переигрывал повторно вживую: Validate CI уже подтвердил его зелёным на этом самом SHA6ac513ca(ссылка выше), а не на другом; вместо повторного полного прогона лично выполнен целевойtest/hp-dialog-contract.test.mjs.
Вердикт
Зелёный. Разбор — полный (ребейз, §7.2), но не «с нуля»: доказано диффом, что код байт-в-байт идентичен
уже одобренному материалу r1, и это доказательство переподтверждено собственными прогонами гейтов, смоков
и мутантов на текущем SHA 6ac513ca, а не принятием чужого вердикта на веру. Находок нет. Раунд не
образует цикл (§4) — вердикт зелёный.
Материал раунда
- Ветка:
issue/508-summary-dialog-scroll, коммитe23d742cd508— ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Дерево материала:
5fc02b5d1de102ed9770f28fc5eb3a41098cbc11git log --all --format='%H %T' | grep 5fc02b5d1de1 - Вердикт конвейера:
green· High 0