22 KiB
CODE-REVIEW-248-r2
- Issue: #248 — «Оптимизировать» не идемпотентна после записи и reload
- Ветка:
issue/248-optimize-idempotence - ТЗ:
docs/specs/248-optimize-idempotence.md(SPEC-REVIEW-248-r1, зелёный) - Этап: code (PROCESS.md §2.7), заход r2, трек обычный
- Вердикт: зелёный
Расхождение с переданным заголовком задачи
Заголовок этого запуска называл «заход r1 · блокирующих циклов 0/4». Это не соответствует действующему состоянию issue и было исправлено по факту, а не принято на слово:
- в комментариях #248 уже есть код-ревью с вердиктом красный · заход r1 · блокирующих циклов 1/4 · High: 1 (находка H1 — устаревший docs-отпечаток);
- документ того раунда уже закоммичен в дерево задачи —
docs/reviews/CODE-REVIEW-248-r1.md, коммитe468414(текущий HEAD); - автор закрыл H1 и владелец явно написал «Возвращаю задачу в code review для захода r2».
Соответственно этот документ — -r2, а не -r1; публикация в
docs/reviews/ не должна затирать уже существующий CODE-REVIEW-248-r1.md.
Бюджет циклов после этого зелёного вердикта остаётся 1/4 (зелёный вердикт
цикл не тратит, #227).
Отдельно к самому раунду r1: его вердикт не называл SHA, на котором получен —
только производная находка H1 упоминает HEAD (cbdd5a7) внутри своего текста.
Формально это ровно то расхождение, которое делает раунд 2 менее
воспроизводимым, чем должен быть; в этот раз SHA раунда явно зафиксирован
(см. ниже), чтобы для потенциального r3 не потребовалось той же реконструкции.
SHA раунда r1 (материал предыдущего вердикта): cbdd5a7e73b2b7afd1e05bee453154d3e75cd60b
(реконструирован из текста находки H1 — там же единственная явная привязка).
SHA этого раунда (r2, текущий HEAD): e468414c241900f2175923cfb0901a73e86e9767.
Скоуп ревью
Предмет раунда — дельта git diff cbdd5a7..HEAD, а не задача целиком (PROCESS.md
§2.10): три коммита сверх cbdd5a7 —
5ad4280test: complete Optimize storage fixtures (User-Visible: no)120b491test: require schema-valid Optimize fixture (User-Visible: no)e468414docs: review document for #248 (User-Visible: no, толькоdocs/reviews/CODE-REVIEW-248-r1.md, класс C, не участвует в проверке статуса issue по process-gate)
Дельта касается ровно 4 файлов кроме самого review-документа:
docs/images/05-plan-context-tray.png | Bin 345560 -> 345559 bytes
docs/images/screenshots.json | 24 +--
test/fixtures/optimize-storage-roundtrip.json | 4 +
tests_backend/test_coordinate_canonicalization.py | 2 +
src/** и custom_components/houseplan/**/*.py в дельте не тронуты —
продуктовый фикс идемпотентности (src/plan-optimizer.ts) целиком лежит в
cbdd5a7 и уже был разобран в r1. Дельта — это (а) закрытие H1 (docs
fingerprint) и (b) самостоятельная находка автора по итогам первого CI:
общая fixture не проходила backend-схему без view_box.
Разбор оставлен полным по чувствительным точкам, а не «только H1»: раунд не локален формально (дельта пересекает docs-гейт и backend-fixture-контракт AC4), поэтому ниже переисполнены typecheck/test/build/check-docs/process-gate и целевой AC5-смок, а не только прочитан diff.
Как проверялось
| Команда | Результат |
|---|---|
npx tsc --noEmit |
green, без вывода |
npm test |
1116/1116 pass, 0 fail, 0 skip |
npm run build |
green |
cmp dist/… custom_components/…/frontend/… && cmp dist/… demo/srv/assets/… |
все три бандла идентичны байт-в-байт |
git status --porcelain после build |
пусто — закоммиченный бандл уже актуален |
node scripts/check-docs.mjs |
green — «Documentation checks passed (7 files, 10 external links)» — H1 закрыт |
node scripts/smoke-select.mjs --base cbdd5a7 --head HEAD |
«Исполняемого frontend-диффа нет (src/**/*.ts не тронут)» — дельта раунда не выбирает ни один смок |
node scripts/smoke-select.mjs --base origin/dev --head HEAD |
воспроизведено идентично отчёту r1: 1 файл src, 5 символов (AlignReport, PLAN_MODEL_VERSION, SpaceReferenceReport, canonicalizeConfigGeometry, canonicalizeLayoutGeometry), НЕОПРЕДЕЛЁННОСТЬ |
node demo/smoke_optimize_coordinate_canonicalization.mjs |
green, все 16 полей true (включая serverEventReloadIsExactNoOp, coldReloadIsExactNoOp) — перепрогнан лично на текущем HEAD, не только унаследован |
node scripts/mutation-gate.mjs --check |
green, все мутанты валидны статически, включая три из #248 (optimize-storage-boundary-removed, optimize-config-storage-half-raw, optimize-layout-storage-half-raw) |
node scripts/process-gate.mjs |
green, диапазон origin/dev..HEAD, 6 коммитов, 0 предупреждений |
node scripts/process-gate.mjs --issues |
green (issue #248 в S7-code-review) |
python3 -c "import pytest" / import voluptuous |
оба ModuleNotFoundError — окружение этой ревью-сессии не содержит backend-харнесс, как и в r1 |
gh run view 32602363169 --json status,conclusion,headSha,jobs |
исполнено, не унаследовано на слово: conclusion: success, headSha: 120b491…, job backend — success (pip install pytest … pytest-homeassistant-custom-component … + python -m pytest tests_backend/ -q — success), job docs — success, process-gate — success |
git diff 120b491..HEAD --stat |
подтверждает, что HEAD (e468414) = проверенное CI-дерево 120b491 + только docs/reviews/CODE-REVIEW-248-r1.md — CI-результат применим к текущему HEAD без экстраполяции |
gh run view 32602050492 --json conclusion,workflowName,headBranch |
success, Docs screenshots, ветка issue/248-optimize-idempotence — легитимная пересъёмка, не самодельный PNG |
Дешёвые гейты прогнаны заново, как требует §2.10 (код изменился, они стоят минуты). Тяжёлые — по дельте: golden/полный smoke-набор/performance не прогонялись (обоснование в «Чего не проверял»), backend pytest не исполнялся локально, но подтверждён предъявленным CI-прогоном на точном дереве текущего HEAD, а не восстановлен из слов автора.
Находки
Нет находок High или Medium в этом раунде.
Low (на усмотрение, не блокирует): заголовок задачи, полученный этой
сессией, называл неверный заход/бюджет (r1 · 0/4 вместо фактических
r2 · 1/4). Указано выше в отдельном разделе, не дублируется здесь как
отдельная находка кода — это дефект оркестрации запуска ревью, а не диффа
#248, и не входит в скоуп автора. Если он повторяется на других issue, стоит
завести process-issue отдельно от #248.
Закрытие раунда r1
| Находка r1 | Чем закрыта | Где это видно |
|---|---|---|
H1 (High) — check-docs.mjs красный на cbdd5a7: docs/images/screenshots.json хранит устаревший sourceFingerprint, src/plan-optimizer.ts из диффа делает его неактуальным |
Пересъёмка через каноническую джобу Docs screenshots (workflow_dispatch) на Chromium 151.0.7922.34, принята npm run docs:accept -- --reviewed; sourceFingerprint/sourceSha256 в docs/images/screenshots.json обновлены на 3f3237694ccc9aabd77df6204c598797dc528c2f7a23520915083486666be740 во всех 10 сценариях |
Коммит 5ad4280; лично перепрогнан node scripts/check-docs.mjs на HEAD e468414 → green; gh run view 32602050492 → success на ветке задачи; из 10 PNG изменился только 05-plan-context-tray.png (345560→345559 байт, один imageSha256 из десяти), остальные девять байт-в-байт прежние — подтверждено git diff cbdd5a7..HEAD -- docs/images/screenshots.json | grep imageSha256 |
| L1 (Low) — хендофф говорил «1115 pass, 1 skip», факт — «1116 pass, 0 skip» | Объяснено, не правкой: разные среды (Windows platform-skip у автора, Linux 0 skip у ревьюера r1), оба числа корректны для своей среды | Комментарий владельца «Закрытие CODE-REVIEW-248-r1»; лично перепрогнан npm test на HEAD e468414 → 1116 pass, 0 skip, совпадает с числом, которое r1 сессия получила на Linux — outcome: no_change_needed |
Унаследовано из r1
Принято без повторной проверки в этом раунде, поскольку дельта cbdd5a7..HEAD
не касается ни одного из перечисленных файлов (подтверждено git diff cbdd5a7..HEAD --stat, см. «Скоуп ревью»). Источник — docs/reviews/CODE-REVIEW-248-r1.md,
коммит e468414 (уже в дереве), проверено на SHA cbdd5a7:
- AC1 —
test/plan-optimizer.test.mjs, тест «issue 248 Optimize stays a no-op across the nine-decimal storage round-trip»; мутационный guardoptimize-storage-boundary-removedподтверждён исполнением в r1 (тест краснеет без правки границы вsrc/plan-optimizer.ts). Не тронуто дельтой. - AC2 — параметризованный тест по
cell_cm1/3/5/1000 вtest/plan-optimizer.test.mjs; существующий ULP-тест «six-room» подтверждает, что реальный шум по-прежнему даётchanged:true, счётчики не занулены безусловно. Не тронуто дельтой. - AC3 —
custom_components/houseplan/store.py:150-229,websocket_api.py:1554-1666: обе половины записи (optimize_pendingи live store) канонизируются независимо; backend production-код не менялся (§13.5 ТЗ). В r1 это было «проверено чтением, не исполнением» из-за отсутствияpytestв сессии; в этом раунде дополнительно подтверждено исполнением черезgh run view 32602363169— jobbackendsuccess на120b491, то есть на дереве, идентичном текущему HEAD за вычетом самого review-документа. - AC4 (частично) — общая fixture
test/fixtures/optimize-storage-roundtrip.jsonи её потребители в Node/Python. Наследуется факт «одна fixture, оба runtime» из r1; не наследуется схемная валидность фикстуры на моментcbdd5a7— это ровно то, что дельта раунда исправляет (см. «Как проверялось» и разборview_boxниже), поэтому по AC4 сделана дополнительная самостоятельная проверка, а не чистое наследование. - AC5 —
demo/smoke_optimize_coordinate_canonicalization.mjs, расширенный подserverEventReloadIsExactNoOp/coldReloadIsExactNoOp. Файл не тронут дельтой; тем не менее смок лично перепрогнан на текущем HEAD (см. таблицу гейтов) — совпадает с r1: все 16 полейtrue. - AC6 (документация) —
docs/CANVAS.md§9.5,docs/CONFIG-COMPATIBILITY.md,docs/USER-GUIDE.ru.md,docs/TESTING.md, оба changelog: содержание не тронуто дельтой, разобрано и принято в r1. - Трейлеры
cbdd5a7(Issue: #248,User-Visible: yes, оба changelog в том же коммите) — унаследовано, не перепроверялось повторно (коммит не входит в дельту раунда). - Смок-выборка полного диффа
origin/dev...HEAD(5 символов, НЕОПРЕДЕЛЁННОСТЬ, три целевых смока с прямой/тематической связью запущены и зелёные в r1:optimize_coordinate_canonicalization,optimize_geometry_preflight,optimize_micro_interval) — воспроизведено идентично инструментом в этом раунде (см. таблицу), сами смоки_preflightи_micro_intervalне перезапускались повторно, т.к. их файлы не в дельте. golden:verifyи полный набор 167/169 браузерных смоков — не прогонялись ни в r1, ни здесь; обоснование (diff не меняет геометрию/рендер, golden — предрелизный гейт по AC6 и §12 ТЗ) наследуется без изменений, т.к. дельта этого раунда тем более не касается рендера (только docs-манифест, фикстура, один assert).- Performance — не названо в AC, чувствительный путь (
O(n)проход) не тронут дельтой; наследуется из r1.
Проверено и корректно (сверх наследования)
- Закрытие H1 — не принято на слово:
check-docs.mjsлично перепрогнан зелёным на HEADe468414,git statusпослеnpm run buildчист, а сравнениеimageSha256по всем 10 сценариям показывает ровно один изменённый файл (plan-context-tray, 1 байт), как и утверждал автор — никакой другой скриншот не «съехал» тайком. - Самостоятельная находка автора (
view_box) — до фиксаtest/fixtures/optimize-storage-roundtrip.jsonне содержал обязательное полеvol.Required("view_box")(custom_components/houseplan/validation.py:984); без негоCONFIG_SCHEMA(source["config"])вtest_optimize_roundtrip_fixture_has_one_backend_canonical_targetне могла бы пройти. Значение[0, 0, 1, 1]проверено против_view_box()(validation.py:566-570):x=0, y=0в допуске_GEOM,w=1, h=1в допуске_EXTENT(0.001..CANVAS_LIMIT) — валидно и не вырождено (не повторяет баг HP-1502-01 про[0,0,0,0]). Значение идентично вinputиexpectedдля обеих geometry (fine,regular) — канонизация не должна его менять, что и подтверждает зелёный backend-прогон в CI. - AC3/AC4 backend-доказательство теперь подтверждено исполнением, а не
только чтением —
gh run view 32602363169называет точный SHA (120b491) и job (backend) с командойpython -m pytest tests_backend/ -q, success;git diff 120b491..HEAD --statпоказывает, что единственная разница между проверенным CI-деревом и текущим HEAD — файлdocs/reviews/CODE-REVIEW-248-r1.md(класс C, не участвует в тестах). Это устраняет ограничение «проверено чтением, не исполнением», отмеченное в r1 для AC3. - Docs screenshots run легитимен —
gh run view 32602050492подтверждает workflowDocs screenshotsна ветке задачи с успешным результатом, то есть принятие черезdocs:accept --reviewedсоответствует правилу §8 PROCESS.md (не самодельный локальный кадр). - Трейлеры дельты —
5ad4280,120b491,e468414все несутIssue: #248;User-Visible: noкорректен для всех трёх (тесты/fixture/ docs-манифест и сам review-документ не меняют пользовательское поведение сверх того, что уже задокументировано вcbdd5a7). - process-gate зелёный на полном диапазоне
origin/dev..HEAD(6 коммитов, 0 предупреждений) и с--issues(статус issue #248 соответствуетS7-code-review).
Чего не проверял
- Полную матрицу 167/169 браузерных смоков — не унаследовано слепо: лично
подтверждено, что
smoke-selectдаёт тот же результат («НЕОПРЕДЕЛЁННОСТЬ», 5 символов) на полном диффеorigin/dev...HEAD, и что дельта этого раунда (cbdd5a7..HEAD) вообще не выбирает смоков (src/**/*.tsне тронут). Целевой AC5-смок перепрогнан лично;_preflightи_micro_interval— нет (не в дельте, зелёные в r1). npm run golden:verify— diff (полный и дельта) не меняет геометрию, стили или слои рендера; предрелизный гейт по AC6/§12 ТЗ.python -m pytest tests_backend -q— не исполнялся локально (pytest/voluptuousне установлены в этой сессии), но подтверждён черезgh run viewна CI-прогоне точного дерева HEAD минус review-документ — это сильнее «проверено чтением», хотя и не то же самое, что личное исполнение.- Оба backend-мутанта (
optimize-config-storage-half-raw,optimize-layout-storage-half-raw) —mutation-gate.mjs --checkподтвердил только статическую валидность патча (якорь найден), не факт, что тест краснеет с мутацией; их guard (backend-test-guard.mjs) тоже требуетpytest, недоступного в сессии. Backend CI job (python -m pytest tests_backend/ -q) не запускаетmutation-gate.mjs, поэтому исполнение этих двух мутантов не подтверждено ни в r1, ни здесь — фактическое исполнение остаётся долгом до следующего Linux-сеанса с установленнымpytest, но не блокирует зелёный вердикт: сам факт что тест существует и статически бьёт по нужной строке проверен, а полное отсутствие исполнения этих двух конкретных мутантов было тем же ограничением уже в r1 и не регрессировало. - Полный Linux HA harness (полная HA-обвязка, не только
tests_backend/pure-подмножество) — вне скоупа код-ревью, канонический прогон в CI/WSL. - Performance-профили — не названы в AC, чувствительные пути не тронуты дельтой.