18 KiB
CODE-REVIEW-663-r3
Материал раунда: f2e114d71dba9e34242e63e92781ecffa9b3f730 (ветка
issue/663-stairs, рабочая копия уже на нём). Предыдущий материал (r2):
d64338224da8606bf2b346906b8f6f2a9bd0a15e.
Дельта: git diff d6433822..f2e114d7 — 3 содержательных коммита (плюс
8176f119 — публикация CODE-REVIEW-663-r2.md, класс C, не код):
8852207btest: стабилизировать проверку угла magnet лестницы—demo/smoke_stairs.mjs(+5/-1);9755b200chore(golden): принять разметку обратной лестницы—demo/golden/baselines/baselines-index.json(+14/-14) и 4 PNG (stairs-flat-normal-light,stairs-flat-hover-dark,stairs-flat-selected-light,stairs-isometric-dark);f2e114d7docs: обновить fingerprint скриншотов после лестниц—docs/images/screenshots.json(+12/-12, толькоsourceFingerprint/sourceSha256,imageSha256не менялись).
Заход: r3 (код-ревью), блокирующих циклов израсходовано 2/4.
dev не сдвинулся с r1/r2: git merge-base HEAD origin/dev ==
origin/dev == cf876c71 (та же база). Дельта не трогает ни одного файла
класса A (src/**, custom_components/**/*.py) — node scripts/process-gate.mjs --range d6433822..HEAD --issues подтверждает:
«файлов класса A нет». Это чисто дельта-раунд: закрывает ровно две
Medium-находки CODE-REVIEW-663-r2.md, продуктовый код не менялся с r2.
Разбор — по дельте, а не заново; общий скоуп задачи (#663, J1/J4/J6 по
docs/SCOPE.md) не пересматривается — см. CODE-REVIEW-663-r1.md/-r2.md.
Закрытие раунда r2
| Находка r2 | Чем закрыта | Где это видно |
|---|---|---|
Medium-1 — golden-эталон устарел для 4 сцен с лестницами (direction:'backward'), AC12 не доказан на материале r2 |
9755b200: приняты 4 новых baseline PNG + baselines-index.json обновлён (sourceFingerprint, localAttestation, 4 новых scenarios-хэша). Коммит несёт Release: v1.78.0-beta.5 + Baseline-Reviewed-Local: sha256:d6725147cfe96217ca01c22b86bc05eb4b69dd9c73402d88b57e071adfb4e181 — ровно тот путь, что назвал r2 (прецедент 93876d75/ac6f4bfe) |
Лично прогнал npm run bundle:sync && npm run golden:verify на этом точном SHA: 179 passed, 0 different, все 4 сцены лестниц в списке — stairs-flat-normal-light, stairs-flat-hover-dark, stairs-flat-selected-light, stairs-isometric-dark — passed. Trailer-хэш d6725147… совпадает с localAttestation.sha256 в самом индексе — не рассинхронизирован |
Medium-2 — smoke-свидетель wallMagnetUsesPhysicalFace статистически ненадёжен (баг сравнения угла по модулю 180 для отрицательного эпсилон) |
8852207b: старое closeTo(((angle % 180) + 180) % 180, 0) заменено на axisAngleDistance(angle) = Math.min(normalized, 180 - normalized) — ровно паттерн, который r2 указал как уже существующий в дереве (src/junction-limits.ts:200-204) |
Математически воспроизвёл ровно случай из r2 (node -e): для angle = -2.2737367544323206e-13 старая формула давала 179.999999999999773 → closeTo(…, 0) === false (подтверждает исходный баг); новая axisAngleDistance даёт 2.27e-13 → true, и для +2.27e-13 — тоже true (симметрично). Проверил, что фикс не «обнуляет» дискриминацию теста: axisAngleDistance(45) = 45, (90) = 90, (179.5) = 0.5 — все корректно false, тест по-прежнему ловит реально не-осевой угол. Лично прогнал node demo/smoke_stairs.mjs 30 раз подряд (два прогона по 15, разными вызовами) на свежем bundle:sync этого SHA — wallMagnetUsesPhysicalFace: true и итоговый OK 30/30, ни одного красного (было 3 красных из 13 на материале r2) |
Обе находки закрыты не на слово автору: golden — личным golden:verify на
точном SHA с явной проверкой каждой из 4 сцен построчно; smoke-формула — и
математической реконструкцией конкретного числа из r2, и живым 30-кратным
прогоном браузерного смока.
Унаследовано из r2 без повторной проверки
Дельта не касается этих областей — приняты по CODE-REVIEW-663-r2.md
(материал d6433822, вердикт жёлтый, High 0) и, транзитивно, по
CODE-REVIEW-663-r1.md (материал 59a60d52, вердикт жёлтый, High 0) без
повторного разбора:
- continuous/мебельный transform-контракт лестниц (
src/stairs.ts,src/coordinate-canonicalization.ts), включая закрытый в r1 High-1; - разметка ступеней для
direction:'backward'(Medium-1 из r1, продуктовый фиксsrc/stairs.ts:151-157— сам код дельтой r2→r3 не тронут, менялся только его эталонный скриншот); - mutation witnesses AC7/AC11 (
stairs-broken-targets-become-active,stairs-legacy-config-materializes-empty-collection,stairs-import-skips-target-space-remap); - backend-схема (
validation.py, лимит 250), repair ссылки при удалении пространства, import/export remap; - i18n (4 языка), 2D/2.5D через общий floor-projection слой, батчинг
вычитания площади по кадрам (
ea1f19c3), navigation/gesture guard'ы; - документация (
STAIRS.md,CANVAS.md,UX-MODES.md,CONFIG-COMPATIBILITY.md,TOUCH-SUPPORT.md), трейлеры и changelog предыдущих коммитов.
Как проверялось
Обязательный Validate точного SHA материала — зелёный:
https://github.com/Matysh/houseplan-card/actions/runs/36279695032. Проверил
job-список построчно (gh run view 36279695032 --json jobs): зелёные —
предпролёт, классификация, переиспользование, frontend
(types+unit+build+bundle-sync), мутанты по диффу (6/6 шардов),
«доказательство выполненных проверок»; skipped — hacs, hassfest,
geometry_parity, backend (pytest), смоки в браузере, golden,
performance_smoke, бандл dev для стенда. node scripts/classify-changes.mjs --heavy на этом HEAD лично подтверждает heavy=false — эти heavy-джобы
skipped корректно (сам head-коммит f2e114d7 не несёт Release:; тот
трейлер есть только у среднего коммита дельты 9755b200, а heavy-флаг
смотрит на head), значит golden/browser-smoke Validate не подтверждал и они
остаются моей обязанностью — прогнаны ниже лично.
| Гейт | Прогнано | Результат |
|---|---|---|
npx tsc --noEmit |
лично, на этом SHA | зелёный, без ошибок |
npm run build (+ bundle:sync) |
лично, дважды (для golden и для смоков) | оба раза created dist без ошибок |
npm test |
лично, на свежем build | # tests 3143 / pass 3142 / fail 0 / skipped 1 — совпадает с зафиксированным в r2 базовым числом |
| Мутанты по диффу (6/6 шардов) | зачтено по зелёному Validate этого SHA (дельта не содержит новых мутантов реестра — только правка существующего теста и golden/docs) | все 6 шардов success |
node scripts/check-docs.mjs |
лично | Documentation checks passed (7 files, 12 external links) — 0 warn (в r2 был 1 ожидаемый warn про устаревший fingerprint; коммит f2e114d7 дельты его и закрывает) |
node scripts/check-docs.mjs --screenshots=strict |
лично | тоже зелёный, без расхождений |
node scripts/validate-commit-provenance.mjs |
лично, по диапазону дельты | без вывода/ошибок — трейлеры всех 3 коммитов дельты валидны (Issue:#663+User-Visible:no на всех трёх; Release+Baseline-Reviewed-Local на 9755b200, ровно один из двух допустимых) |
node scripts/smoke-select.mjs --base d6433822 --head f2e114d7 |
лично | «Исполняемого frontend-диффа нет (src/**/*.ts не тронут). Browser-smoke этим диффом не выбираются» — ожидаемо: дельта не трогает src/** |
node demo/smoke_stairs.mjs (AC2-свидетель, названный в r2 как ненадёжный) |
лично, 30 последовательных прогонов на свежем bundle:sync этого SHA |
30/30 OK, wallMagnetUsesPhysicalFace: true во всех 30 — закрывает Medium-2 |
npm run golden:verify (полная матрица, диф трогает golden напрямую) |
лично, на свежем bundle:sync этого SHA |
179 passed, 0 different — все 4 сцены лестниц явно passed, закрывает Medium-1 |
python -m pytest tests_backend -q |
не прогнано | нет pytest/homeassistant в этой ревью-среде (как в r1/r2); дельта r2→r3 не трогает ни одного .py-файла — риск нулевой для этой дельты |
npm run invariants -- --config … |
не прогнано | дельта не меняет модель/геометрию хранения — только тестовую формулу сравнения углов и эталонные PNG/фингерпринты |
После проверки бандл возвращён к закоммиченному состоянию (npm run bundle:clean), git status — пусто.
Один число — один источник: Release: v1.78.0-beta.5 в 9755b200 совпадает
с package.json.version (1.78.0-beta.5) — один источник версии, расхождения
нет. Baseline-Reviewed-Local хэш в трейлере (d6725147…) байт-в-байт равен
localAttestation.sha256 в самом baselines-index.json — не два независимых
числа.
Находки
Нет. Обе Medium-находки r2 закрыты и подтверждены исполнением (не чтением
хендоффа): golden — полным golden:verify на точном SHA с построчной
проверкой всех 4 сцен; smoke — 30 живыми прогонами плюс математическим
воспроизведением точного бага и подтверждением, что дискриминирующая
способность теста не пострадала. Новых находок при обязательном прогоне
названных в AC гейтов (golden, smoke_stairs, npm test, check-docs, provenance)
не появилось.
Итого: High 0, Medium 0.
Что проверено и корректно
- Обе Medium-находки
CODE-REVIEW-663-r2.mdзакрыты доказательно (таблица «Закрытие раунда r2» выше). npm test— 3142 pass / 1 skip / 0 fail (после чистогоnpm run build; число совпадает с зафиксированным в r2).npm run golden:verify— 179/179, 0 расхождений, включая все 4 сцены лестниц, ранее не совпадавшие.node demo/smoke_stairs.mjs— 30/30 подряд, включая ранее нестабильную проверкуwallMagnetUsesPhysicalFace.- Трейлеры всех 3 коммитов дельты корректны (
Issue/User-Visibleна всех, единственныйBaseline-Reviewed-Localна коммите с golden-baseline, совпадает с содержимым индекса);User-Visible: noна всех трёх — оправданно: изменения не меняют наблюдаемое поведение продукта (тестовая формула, эталонные скриншоты, фингерпринт документации), changelog не требуется и не тронут. node scripts/check-docs.mjs(обычный и--screenshots=strict) — зелёный без warn; предыдущий warn r2 про устаревший fingerprint скриншотов закрыт коммитомf2e114d7этой же дельты.node scripts/process-gate.mjs --range d6433822..HEAD --issues— гейт пройден (единственный warn — ожидаемый, про инфраструктурный диапазон без файлов класса A).node scripts/validate-commit-provenance.mjs— без ошибок на диапазоне дельты.- Дельта не расширяет и не сужает скоуп задачи: три коммита строго чинят то, что нашёл r2, никакого нового продуктового поведения не введено (что и подтверждает пустой диапазон класса A).
Побочная заметка не как находка ревью: при личном прогоне npm test
сразу после npm run bundle:clean (восстановление закоммиченного dist)
получил 4 fail в test/bundle-assets.test.mjs (#438/#593/#627,
bundle-graph-budget тесты, не относятся к лестницам) — это оказался артефакт
моего собственного порядка команд (эти тесты читают именно свежесобранный
dist, а не восстановленный committed-копию, ровно как описывает gate:small
в AGENTS.md: «unit tests follow the completed build»). После npm run build без последующего bundle:clean те же 4 теста (и весь набор) — зелёные
(проверил test/bundle-assets.test.mjs отдельно: 36/36 pass). Не находка
материала — фиксирую, чтобы не создавать ложное впечатление регресса в логе
сессии.
Чего не проверял
python -m pytest tests_backend— не прогнано (нетpytest/homeassistantв этой среде, как в r1/r2); дельта r2→r3 не трогает ни одного.py-файла — нулевой риск для этой дельты. Backend-код в целом остаётся проверенным по r1/r2 (см. «Унаследовано»).npm run invariants— не прогонял; дельта не меняет модель/геометрию, только тестовую формулу и эталонные изображения/фингерпринты.- HACS/hassfest/geometry_parity/performance_smoke — skipped на материале (heavy-гейты, ожидаемо), дельта не трогает манифесты, geometry-модель или perf-путь; не прогонял отдельно — уже закрыто по r1/r2 для остального кода, для этой дельты не в фокусе.
- Полная browser-smoke матрица за пределами
smoke_stairs—smoke-selectпо дельтеd6433822..f2e114d7не выбрал ни одного смока (нетsrc/**в дельте);smoke_room_resize/smoke_summary_first_paint(задетые более ранними багфиксами r1/r2) дельтой r2→r3 не затронуты, повторно не гонял. - Мутанты по диффу лично построчно — не перечитывал логи всех 6 шардов
заново (дельта не добавляет новых записей
mutation-registry.mjs; проверил только, что ни один существующий stairs-мутант не таргетируетwallMagnetUsesPhysicalFaceили изменённые golden-сцены — не таргетирует, см. проверкуscripts/mutation-registry.mjsпо всем 11stairs-*id).
Материал раунда
- Ветка:
issue/663-stairs, коммитf2e114d71dba— ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Дерево материала:
682ed825a6708975ff1c3f6c5ef1bb7b5b90960bgit log --all --format='%H %T' | grep 682ed825a670 - Тело issue:
f3f0ee8408eb76ccec4f3ec50a9048ff1e29b2967259f0d4c4d333d8c68157e4 - Вердикт конвейера:
green· High 0