14 KiB
CODE-REVIEW-586-r1
Issue: #586 — Validate: строгий режим свежести скриншотов документации не включается (сравнение с многострочным выводом CLI).
Трек: инфраструктурный (§1 PROCESS.md) — ни один файл класса A не тронут, ТЗ/S1–S6 не требуются.
Материал: 21923c344de012c8849083b68200a6a205a53649 (ветка issue/586-screenshots-strict-mode), два коммита от 303c0843 (dev на момент ветвления):
245b7f98— фикс разбора выводаclassify-changes.mjsвvalidate.yml;21923c34— пересъёмка и приёмка 4 кадров документации (снятый долг #479).
Заход r1, блокирующих циклов израсходовано 0 из 4.
Скоуп диффа
.github/workflows/validate.yml | 10 ++++++----
docs/images/01-view-desktop.png | Bin
docs/images/02-view-touch.png | Bin
docs/images/08-room-card.png | Bin
docs/images/09-device-info.png | Bin
docs/images/screenshots.json | 40 ++++++++++++++++----------------
scripts/classify-changes.mjs | 29 +++++++++++++++++++++++++++-
scripts/mutation-registry.mjs | 15 +++++++++++++++
test/classify-changes.test.mjs | 30 +++++++++++++++++++++++++++++
Все файлы — класс B (гейты/инструменты) и C (документация/скриншоты). Продуктовый код (src/**, custom_components/**) не тронут — классификация «инфраструктурная» верна.
Как проверялось
Читал по порядку: docs/SCOPE.md, PROCESS.md (§1–§10), тело issue #586 и хендофф-комментарий автора, сам диффа. Продуктового поведения нет, поэтому docs/USER-GUIDE.ru.md и канонические документы подсистем нерелевантны.
Гейты — что прогнано и почему
| Гейт | Статус | Комментарий |
|---|---|---|
Validate на 21923c34 |
не перезапускал | Подтверждён вводной задачи как success: https://github.com/Matysh/houseplan-card/actions/runs/35139056409. Дешёвые гейты (tsc, npm test, build+сверка бандла) считаю закрытыми этим прогоном |
node --test --test-name-pattern="#586" test/classify-changes.test.mjs |
прогнан, зелёный | 2/2 pass — оба новых теста-свидетеля |
Мутация вручную (снял защиту так же, как патч в mutation-registry.mjs, прогнал тест) |
прогнан | тест #586: режим гейта скриншотов… покраснел: expected 'strict', actual 'warn'. Working tree восстановлен после проверки (git status чист) |
node scripts/mutation-gate.mjs --id=screenshot-freshness-never-strict |
прогнан, зелёный | ok screenshot-freshness-never-strict: заявленный тест покраснел на мутанте · поймано 1 из 1 — независимое подтверждение официальным гейтом, не только ручной правкой |
node scripts/mutation-gate.mjs --check |
прогнан, зелёный | структурная проверка реестра, включая новый id — без FAIL |
node scripts/check-docs.mjs --external --screenshots=strict |
прогнан, зелёный | Documentation checks passed (7 files, 12 external links) — подтверждает, что отпечаток кадров действительно синхронизирован после второго коммита |
node scripts/no-new-any.mjs --base origin/dev --head HEAD |
прогнан | 0 добавленных строк в src/**/*.ts — неприменимо, но чисто |
node scripts/smoke-select.mjs --base origin/dev --head HEAD |
прогнан | «Исполняемого frontend-диффа нет» — смоки не выбираются, выбирать нечего |
node scripts/process-gate.mjs |
прогнан, зелёный | 2 коммита, диапазон origin/dev..HEAD, предупреждений 0 |
npx tsc --noEmit, полный npm test, npm run build+cmp бандла |
не прогонял отдельно | покрыты зелёным Validate на этом SHA (см. выше); diff не трогает src/**, риска для бандла/тайпчека нет |
npm run golden:verify |
не прогонял | diff не меняет рендер карточки — визуального продуктового результата нет, только скриншоты документации |
python -m pytest tests_backend |
не прогонял | custom_components/**/*.py не тронут |
| performance-профили | не прогонял | не названы в AC, чувствительные пути (src/iso-*, src/live-*, src/render-*) не тронуты |
Находки
Блокирующих (High) находок нет. Medium в скоупе или вне скоупа — нет.
Low, снятая с записью: комментарий во validate.yml («#586: CLI отдаёт ОДИН ответ…») и в classify-changes.mjs дублируют друг друга почти дословно — не мешает читаемости и не влияет на корректность, менять не требую.
AC — построчно
Приёмка из issue:
-
«Свидетель краснеет на текущем коде: при
heavy=trueв выводе из двух строк выбранный режим обязан бытьstrict» — доказано автотестомtest/classify-changes.test.mjs. Таблица «чем краснеет»:AC Чем доказан Чем краснеет AC1 (защитный: старая логика никогда не давала strict)node --test --test-name-pattern="#586" test/classify-changes.test.mjsПатч из mutation-registry.mjsidscreenshot-freshness-never-strict(возвращаетstrictтолько для несуществующего события) — тест падаетexpected 'strict', actual 'warn'; дополнительно подтвержденоmutation-gate.mjs --id=screenshot-freshness-never-strict→ «поймано 1 из 1»Дополнительно тест
assert.notEqual(run(['--heavy'], candidate), 'heavy=true', …)напрямую фиксирует регрессионный факт (вывод--heavyмногострочный), из-за которого баг вообще возник — не дал ему тихо вернуться. -
«Кандидат с устаревшим отпечатком скриншотов краснеет в Validate» — проверено чтением, не исполнением полного Validate:
validate.ymlтеперь вызываетnode scripts/check-docs.mjs --external --screenshots=$mode, где$modeсчитаетscreenshotsGateMode()(классstrictпри трейлереRelease:, PR, schedule,workflow_dispatch full=true). Поведениеcheck-docs.mjs --screenshots=strictна устаревшем отпечатке (падение с ERROR) — уже установленный факт из #479 и подтверждён самим текстом issue («Локально…check-docs.mjs --strictпадает сERROR»); в этом диффеcheck-docs.mjsне менялся. Комбинация «правильное значение считается» (доказано тестом п.1) + «правильное значение используется» (доказано вторым тестом «preflight спрашивает режим одним значением…», который проверяет содержимоеvalidate.ymlчерез regex) закрывает AC2 без необходимости гонять весь Validate. -
«Обычный push остаётся в
warn» — доказано юнит-тестом:screenshotsGateMode({ eventName: 'push', headMessage: 'fix: x…' })→'warn'. -
«Заодно проверить остальные места, где вывод
classify-changes.mjsразбирается сравнением строки целиком» — проверено чтением:grepпо всем.github/workflows/*.ymlиscripts/**на использованияclassify-changes.mjsпоказывает единственный паттерн вида[ "$var" = "…" ]— тот, что был пофикшен. Остальные вызовы (строки 265, 305, 329, 339, 347 вvalidate.yml) пишут вывод в$GITHUB_OUTPUTпострочно (tee -a/>>) — это штатный форматключ=значение, а не сравнение целой строки, и он не задет багом.
Что проверено и корректно
- Второй коммит (пересъёмка скриншотов) — не самостоятельная работа над гейтом «раз уж я здесь»: он прямо мотивирован тем, что включение strict-режима без актуального отпечатка тут же покрасило бы кандидата, а «долг» скопился именно потому, что защита не работала. Это укладывается в рамку задачи, а не расширяет её.
- Приёмка скриншотов — легитимным путём:
docs-accept.mjsподдерживает--expect-change, иdeclaredвscreenshots.json(view-desktop, view-touch, room-card, device-info) совпадает с реально изменившимися 4 файлами из диффа. JSON не редактировался руками мимо инструмента. - Автор задокументировал двойной прогон капчура (11/11 байт-в-байт совпадение) как довод против шума раннера, и визуально сверил 4 разошедшихся кадра (таблица differences ≤0.17%, maxΔ≤17) — качество доказательства выше типового для подобной правки.
- Трейлеры обоих коммитов:
Issue: #586,User-Visible: no— корректно (изменение не меняет наблюдаемое поведение продукта; экран пользователя не задет, правится только CI и скриншоты документации). mutation-registry.mjs: новый idscreenshot-freshness-never-strictсинтаксически и структурно корректен (--checkпроходит), а guard (--test-name-pattern="#586") точечно нацелен на добавленные тесты, не гоняя весь файл.- Working copy после моих проверок чиста (
git status --porcelainпуст) — я не оставил артефактов в репозитории.
Чего не проверял
- Полный
npm test/npx tsc --noEmit/npm run build+cmp — не гонял отдельно, положился на зелёный Validate этого точного SHA (см. таблицу гейтов). golden:verify,pytest tests_backend, performance-профили — не применимы к диффу (не трогает рендер/бэкенд/perf-пути).- Реальный сценарий «Validate на кандидате со специально устаревшим отпечатком краснеет end-to-end» не воспроизводился запуском workflow — закрыт комбинацией юнит-теста + чтения кода (см. AC2 выше), это осознанное решение, а не пропуск.
Материал раунда
- SHA материала:
21923c344de012c8849083b68200a6a205a53649 - Дерево: см.
git show 21923c34^{tree} - Первый раунд — раздел «Унаследовано из r0» не требуется.
Вердикт
Зелёный. AC1–AC4 доказаны (автотест + мутационный гейт + чтение кода), защитный AC имеет полноценную таблицу «чем краснеет» с подтверждением через mutation-gate.mjs, скоуп не расширен, трейлеры корректны, инфраструктурный трек применён правомерно.
Материал раунда
- Ветка:
issue/586-screenshots-strict-mode, коммит21923c344de0— ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Дерево материала:
ebc8db699ad297494bc533175728e18947afef32git log --all --format='%H %T' | grep ebc8db699ad2 - Тело issue:
18937affcac4a9658ede2b880f86cf8f3c1a1e78f4b87f6823d451e5ed313c42 - Вердикт конвейера:
green· High 0