15 KiB
CODE-REVIEW-252-r2
Вердикт: зелёный · заход r2 · блокирующих циклов израсходовано 0 из 4 · High: 0 · Medium: 0
Скоуп раунда: почему это переиздание r2, а не новый разбор с нуля
Этот запуск — повторное проведение того же раунда r2, а не заход r3. Round r2
уже был проведён и опубликован (комментарий issue от 2026-08-23T07:56:33Z,
документ docs/reviews/CODE-REVIEW-252-r2.md, зелёный вердикт, High:0/Medium:0),
но пайплайн не довёл дело до конца: автор сообщил (2026-08-23T07:56:45Z), что
автоматический прогон упал
и статусная метка не переставилась. С точки зрения оркестратора раунд не
завершён (бюджет §4 не потрачен: зелёный вердикт цикл не расходует), поэтому
задача пришла на повторное r2, а не на r3.
Проверено, что переиздавать нечего заново с нуля:
- SHA, на котором был получен предыдущий вердикт r2:
b58136aa2cc943652af5adb8a94047b668d68dc6. - Текущий HEAD:
3741bddc6236ffe3d85965dc630704e578561710. git diff b58136a..HEAD --stat→ ровно один файл:docs/reviews/CODE-REVIEW-252-r2.md | 249 +++++++++++++++++++++++++++++++++++++(1 file changed, 249 insertions(+)) — это САМ ранее опубликованный документ ревью, закоммиченный шагом публикации предыдущего (упавшего после вердикта) прогона. Ни один файлsrc/**,demo/**,docs/CANVAS.mdи т.п. междуb58136aи текущим HEAD не менялся.
Значит, весь код, который уже был полностью разобран в CODE-REVIEW-252-r1
(на пре-ребейзном коммите, полный разбор) и CODE-REVIEW-252-r2 (на
пост-ребейзном b58136a, тоже полный разбор — ребейз на ушедший вперёд dev
подпадает под §7.2), остался байт-в-байт тем же кодом. Дельта этого раунда —
пустая по существу. Полный разбор AC по коду в третий раз подряд на неизменном
дереве был бы именно той «потерей времени», от которой явно предостерегает
инструкция («полные наборы — это предрелизный гейт, а не гейт ревью»).
Дополнительно проверено расхождение с origin/dev, который тем временем ушёл
дальше собственной прошлой проверки в CODE-REVIEW-252-r2 (там уже был учтён
a952f5f/#256 и его review-документ 2d1fca1, оба признаны не пересекающимися
с #252 по файлам). С тех пор dev получил ещё два коммита:
10999a5—ci(process): привести ветку к dev до код-ревью, а не после(#257), правит только.github/workflows/process.yml;4b6331f—docs(process): описать приведение ветки к dev до код-ревью(#257), правит толькоPROCESS.md.
Оба — чистый процесс/CI, ноль пересечения по файлам с диффом #252
(src/space-reference-repair.ts, plan-optimizer.ts, houseplan-card.ts,
styles.ts, i18n, доки CANVAS/CONFIG-COMPATIBILITY/USER-GUIDE, golden-сцены).
Ретроактивно новое правило «ребейзить до ревью» на уже идущий с r1 код-ревью
#252 не распространяется (правило описывает будущий шаг пайплайна перед
следующим запуском ревью, а не требование к уже проверенному коду). Само
слияние ветки #252 в dev, как и раньше, потребует технического ребейза —
это не меняет оценку текущего диффа.
Закрытие раунда r1 (CODE-REVIEW-252-r1)
| Находка r1 | Чем закрыта | Где видно |
|---|---|---|
Low, снято с записью на будущее: мёртвый ключ gs.optimize_reference_warning остался в en.json/ru.json, код его больше не вызывает |
Ключ полностью удалён из обоих словарей коммитом 6c779b5 |
git diff origin/dev...HEAD -- src/i18n/en.json src/i18n/ru.json — строка присутствует только как удаление; test/i18n.test.mjs:77 (assert.doesNotMatch(..., /this\._t\('gs\.optimize_reference_warning'/)) прогнан лично в этом раунде в составе npm test (1140/1140) — зелёный |
Это закрытие не изменилось со времени предыдущего r2 — код тот же самый.
Унаследовано из r1
Полный построчный разбор кода (src/space-reference-repair.ts целиком,
изменённые фрагменты plan-optimizer.ts/houseplan-card.ts/styles.ts,
все юнит- и smoke-тесты, канонические доки, release-артефакты) взят из
CODE-REVIEW-252-r1 (документ в docs/reviews/CODE-REVIEW-252-r1.md, SHA
проверки в этом раунде — b58136aa2cc943652af5adb8a94047b668d68dc6, где этот
разбор был повторён ПОЛНОСТЬЮ заново после ребейза, а не как наследование —
см. раздел «Скоуп» того документа). Наследуется без повторного построчного
чтения в этом раунде:
- классификация владельца (
absent/live-in-missing-space/unverified) — доказательная схема, три исхода, fail-closed при неполном/неавторитетном registry и при неизвестном namespace (AC1–AC3); - отчёт без внутренних id в основном тексте, id — только в свёрнутых «Подробностях» (AC4);
- Preview/Cancel/Apply/Undo и идемпотентность #248 не регрессируют (AC5, AC6);
- осознанное и задокументированное расширение поведения detach у #244
(немедленное авто-удаление stale-позиции заменено общей классификацией;
переименованные тесты и
docs/CANVAS.md/docs/CONFIG-COMPATIBILITY.mdпрямо называют это заменой, а не регрессом); docs/CANVAS.md:494-497заменён (не дополнен), release-артефакты (оба changelog, канонические доки, синхронные bundle-копии) в одном поведенческом коммите сUser-Visible: yes;- golden-семантика двух #252-сцен (
optimize-orphan-references-dark-en,optimize-orphan-references-light-ru), доказанная полнымgolden:verify(97/97) дважды — на пре-ребейзном дереве в r1 и на пост-ребейзномb58136aв r2.
Основание доверять этому наследованию без повторного чтения — не слова автора, а свежая проверка в этом раунде (см. ниже), что дерево с тех пор не изменилось ни на байт.
Как проверялось в этом раунде
Лично прогнано на текущем HEAD (3741bdd), не со слов автора и не по
памяти о прошлых раундах:
npx tsc --noEmit→ чисто, без вывода;npm test→ 1140/1140 pass, 0 fail, 0 skipped (включаетtest/model-invariants.test.mjs— 12/12, в т.ч.#253: исчезнувшая запись толщиныиreadModel понимает экспорт/config/get/сырой config (#254)— обязательный гейт, диф трогает layout-ссылки на пространства);npm run build→ зелёный;sha256sum dist/houseplan-card.js custom_components/houseplan/frontend/houseplan-card.js→e5389ba8e8250c6030fb5365b81619b0d2b4687b4c32f2f2c227ca527b7dbcecдля обеих копий — тот же хеш, что зафиксирован в CODE-REVIEW-252-r1 независимо от меня в этом раунде; совпадение хеша — самостоятельное машинное доказательство того, что исходный код не менялся с r1/r2, а не доверие на слово;npm run bundle:sync→ пересобрал и синхронизировал нетрекаемую стенд-копиюdemo/srv/assets/houseplan-card.js(не коммитится с #255) — зелёно;node scripts/check-docs.mjs→ «Documentation checks passed (7 files, 10 external links)» — обязателен, диф трогаетsrc/**;node scripts/mutation-gate.mjs --check(дешёвый режим, без пересборки бандла на каждого мутанта) → 139/139ok, включая все четыре мутанта этой темы:orphan-space-detach-disabled,orphan-space-ambiguous-signature-guessed,orphan-cleanup-partial-registry-deletes,orphan-cleanup-proven-owners-kept. Дорогой полный прогон (пересборка на каждого мутанта) не повторялся: он уже дважды пройден целиком (r1 — 136/136, r2 — переподтверждён) на этом же дереве, а--checkподтверждает, что реестр патчей и код с тех пор не разошлись;node scripts/smoke-select.mjs --base origin/dev --head HEAD→ те же 6 смоков, что в r1/r2:smoke_orphan_space_references,smoke_grid_snap,smoke_optimize_coordinate_canonicalization,smoke_optimize_geometry_preflight,smoke_optimize_micro_interval,smoke_warm_dialogs; остальные 165 не пересекаются по символам (инструмент не назвал других связей);- все 6 отобранных смоков лично прогнаны headless-Chromium в этом раунде —
все
OK, все булевы поля результатаtrue(в т.ч.idsExistOnlyInClosedDetails,explicitCleanupRebuildsPreviewWithoutWriting,undoRestoresDeadRefsизsmoke_orphan_space_references).
Не повторял в этом раунде (обоснование):
golden:verify(полный, 97 сценариев). Уже пройден целиком дважды в этом же код-ревью: в r1 на пре-ребейзном дереве и в r2 наb58136a— оба раза 97/97, включая обе #252-сцены. Текущее дерево байт-в-байт идентичноb58136a(доказано выше диффом и совпадением SHA-256 бандла). Третий полный прогон на неизменном дереве не добавил бы информации и прямо противоречил бы правилу соразмерности гейтов ревью.mutation-gate.mjsбез--check(полная пересборка на мутанта). По той же причине — уже дважды 136+/136+ на этом дереве,--checkв этом раунде подтвердил отсутствие расхождения.python -m pytest tests_backend— диф не трогаетcustom_components/**/*.py(только сгенерированный JS-бандл в той же папке).npm run invariants -- --config <файл>— точечного экспорта живой инсталляции для этой ветки по-прежнему нет; вместо него —npm testпрогналtest/model-invariants.test.mjsна всех fixture-моделях проекта (см. выше), это тот жеcheckReferences, что стоит за флагом.- Performance-профили — не названы в AC8, путь maintenance-only, не render loop (§12 ТЗ).
- Ручное браузерное тестирование — не входит в конвейер ревью; заменено headless smoke (свежепрогнанные) и дважды пройденным полным golden.
Находки
Нет находок уровня High или Medium. Low-находка r1 (мёртвый i18n-ключ) закрыта — см. таблицу выше.
Итог
Код не изменился с зелёного вердикта предыдущего r2 (b58136a) ни на
байт — единственная разница в дереве это сам ранее опубликованный документ
ревью. Этот раунд — техническое переиздание того же вердикта после сбоя
пайплайна на шаге после публикации (перестановка метки), а не пересмотр
кода. Все дешёвые гейты, обязательные для каждого раунда, лично прогнаны
заново на текущем HEAD и зелёные, включая независимое совпадение SHA-256
собранного бандла с зафиксированным в r1. AC1–AC8 остаются подтверждёнными
полным разбором r1/r2 (см. «Унаследовано из r1» и исходные документы).
Дрейф origin/dev (#256, #257) не пересекается с диффом #252 и не требует
пересмотра. Новых issue не требуется.