Files
houseplan-card/docs/reviews/CODE-REVIEW-441-r1.md
T
2026-09-03 19:46:13 +00:00

16 KiB
Raw Blame History

CODE-REVIEW — issue #441 · заход r2

Ветка issue/441-vacuum-route-draft, HEAD на ревью 75478905 (проверено git rev-parse HEAD непосредственно перед выводом, §2.7).

Почему это заход r2, а не r1

Заголовок задачи, переданный этой сессии, утверждает «заход r1 · блокирующих циклов 0 из 2». Это не подтверждается материалом:

  • в комментариях issue #441 уже есть терминальный вердикт код-ревью: Вердикт: жёлтый · заход r1 · блокирующих циклов 1/2 · High: 0 · Medium: 1 → в задаче (комментарий claude, IC_kwDOTOcLQM8AAAABSa2lLw, 19:35:18 UTC);
  • следом (19:35:28 UTC) владелец подтвердил: «Автоматическое ревью не отработало… Статусная метка не менялась» — то есть вердикт реальный, но шаг конвейера, переставляющий метку после вердикта (§10.4), не выполнился, и задача осталась висеть в S7-code-review, откуда её забрала эта сессия повторно;
  • полный документ того раунда уже закоммичен в ветку самим конвейером (75478905 docs: review document for #441, автор claude[bot]) — это штатный механизм публикации (§10.4: «кладёт документ в docs/reviews/ ветки задачи»), не постороннее вмешательство;
  • SHA того раунда назван в документе — fa41d298 — и он не осиротел: git diff fa41d298..HEAD резолвится и виден ниже.

Таким образом это второй заход ревью, разбор — по дельте (§2.10), а не заново. Файл docs/reviews/CODE-REVIEW-441-r1.md уже существует, второй документ с тем же номером затёр бы его, поэтому этот — r2. Присвоенный этой сессии заголовок «r1 · 0/2», видимо, следствие того же сбоя конвейера, который не переставил метку: трекер раундов не увидел уже опубликованный r1. Само по себе это не код-находка issue #441 и не блокирует вердикт, но чтобы бюджет §4 не потерялся — ниже он посчитан по факту (см. «Вердикт»), а не по переданному заголовку.

Материал предыдущего раунда

  • Документ: docs/reviews/CODE-REVIEW-441-r1.md (в этой же ветке, коммит 75478905).
  • SHA раунда: fa41d298 (fix: keep vacuum routes pending until a floor is chosen).
  • Вердикт r1: жёлтый, High 0, Medium 1 в скоупе — красный check-docs.mjs на fa41d298 (устаревший отпечаток скриншотов документации).

Дельта r1 → r2

git diff fa41d298..HEAD --stat
 docs/images/screenshots.json       |  25 ++--
 docs/reviews/CODE-REVIEW-441-r1.md | 246 +++++++++++++

Два файла, оба класса C (документация/артефакт ревью). Продуктовый код (src/**), тесты и смоки, тронутые в fa41d298, дельтой r1→r2 не задеты — git diff fa41d298..HEAD -- src test demo scripts docs/CHANGELOG.md docs/CHANGELOG.ru.md пуст. Это делает дельту локальной по §2.10: полный повторный разбор AC не требуется, только проверка закрытия находки r1 плюс дешёвые гейты.

docs/reviews/CODE-REVIEW-441-r1.md — служебный артефакт публикации предыдущего раунда, не правка автора; содержательного разбора не требует.

Закрытие раунда r1

Находка r1 Чем закрыта Где это видно
Medium: node scripts/check-docs.mjs красный на fa41d298 — отпечаток скриншотов документации устарел после правки src/editors/vacuum-maps-section.ts Коммит 0ea9c0f5 docs: refresh canonical screenshots for #441 обновил sourceFingerprint/sourceSha256 в docs/images/screenshots.json на все 10 сценариев; imageSha256 каждого сценария не изменился (диалог, который правит #441, ни в одном сценарии не рендерится — пиксели те же), манифест получил acceptance.lastWriteWasFingerprintOnly: true — след легитимной приёмки scripts/docs-accept.mjs (fingerprint-only ветка acceptedDocsManifest, docs-accept.mjs:107), а не самодельной правки JSON git diff fa41d298..HEAD -- docs/images/screenshots.json; перепрогнан node scripts/check-docs.mjs на HEAD 75478905 → Documentation checks passed (7 files, 10 external links) (было ERROR screenshot source fingerprint is stale)

Находка закрыта корректно и через штатный инструмент приёмки (docs-accept.mjs, а не ручная правка screenshots.json мимо проверки совпадения пикселей) — именно та дисциплина, которую требует §8 («скриншоты снимаются только… принимаются локально docs:accept»).

Унаследовано из r1

Без повторной проверки принято (документ docs/reviews/CODE-REVIEW-441-r1.md, материал — SHA fa41d298, тот же SHA подтверждён этой сессией как резолвящийся предок HEAD):

  • AC1 (черновик до выбора этажа) — доказательство beginVacuumRouteDraft (src/vacuum-route-edit.ts:34) и test/vacuum-routes.test.mjs:279 — код не менялся дельтой; для собственного спокойствия эта сессия всё же независимо повторила мутацию r1 (не обязательна по §2.10, сделана как дешёвая проверка): временно заменила space: routes.length ? '' : dockSpace на space: dockSpace, пересобрала test-build (npx tsc -p tsconfig.test.json && node scripts/fix-test-build.mjs) и прогнала node --test test/vacuum-routes.test.mjs → not ok 25 - новый маршрут живёт в черновике до выбора этажа (#441 AC1), # fail 1; откат мутации вернул # pass 32 / # fail 0. Рабочее дерево после отката чисто (git status --short пуст). AC1 подтверждён на текущем SHA, а не только унаследован по документу.
  • AC2 (только валидная атомарная запись) — commitVacuumRouteDraft (src/vacuum-route-edit.ts:39-56), test/vacuum-routes.test.mjs:287, смоки noEmptySpaceEverSubmitted/rejectedPayloadWasValid/ retryKeepsExactIdentity — код не менялся, наследуется по документу r1.
  • AC3 (отмена/отказ не оставляют фантом) — persistRoutes/confirmDraft (src/editors/vacuum-maps-section.ts), смоки cancelLeavesAcceptedRoutes/rejectionRestoresAcceptedMarker/ rejectionKeepsEditorUsable — код не менялся, наследуется по документу r1.
  • Наблюдение r1 про побочное усиление retarget/drop (переход на общий persistRoutes/rollbackOptimistic) и про отсутствие новых ключей i18n — без изменений, код не тронут дельтой.
  • Оценка docs/SCOPE.md (J4/J6) — без изменений, продуктовый скоуп не менялся.

Гейты — что прогнал в этом раунде и с каким результатом

Дельта r1→r2 не трогает src/**/test/**, поэтому по §2.10 достаточно дешёвых гейтов; они прогнаны заново на HEAD 75478905, а не унаследованы:

Гейт Команда Результат
Typecheck npx tsc --noEmit чисто, без вывода
Тесты npm test # tests 1857 · # pass 1856 · # fail 0 · # skipped 1 — совпадает с заявленным в r1
Сборка + синхронизация бандла npm run build, затем git status --short dist пересобран, working tree чист после сборки — dist/houseplan-card.js и custom_components/houseplan/frontend/houseplan-card.js совпадают в коммите (cmp → без вывода, идентичны)
Документация node scripts/check-docs.mjs зелёный: Documentation checks passed (7 files, 10 external links) — находка r1 закрыта (см. выше)
Мутация AC1 (доп. проверка этого раунда) временный откат src/vacuum-route-edit.ts:34 → space: dockSpace, npx tsc -p tsconfig.test.json && node scripts/fix-test-build.mjs && node --test test/vacuum-routes.test.mjs not ok 25 на мутанте, # pass 32 / # fail 0 после отката — дисциплина «тест умеет падать» подтверждена независимо
Смок AC1–AC3 node demo/smoke_vacuum_route_draft.mjs (после npm run bundle:sync, иначе смок падает на отсутствующем demo/srv/assets/houseplan-card.js — сгенерированный, не коммитится, #255) все 14 проверок true, OK

Не прогонялись повторно (дельта их не задевает, обоснование см. в документе r1, наследуется): smoke-select.mjs по полному диффу, golden:verify, pytest tests_backend, npm run invariants, performance-профили, остальные точечные смоки (smoke_vacuum_firstuse, smoke_vacuum_multifloor, smoke_save_race, smoke_config_writer) — их результат на fa41d298 уже зафиксирован в r1 и код, который они покрывают, не менялся.

Трейлеры дельты: 0ea9c0f5 — Issue: #441, User-Visible: no (верно: обновление служебного отпечатка, а не пользовательского поведения, changelog не требуется); 75478905 — Issue: #441, User-Visible: no (служебный артефакт публикации ревью, класс C).

Находки

Нет. Единственная находка r1 (Medium, в скоупе) закрыта корректно и через штатный инструмент. Новых находок дельта r1→r2 не вносит — она состоит из точечного обновления отпечатка документации и служебного коммита самого конвейера.

Что проверено и корректно (без отдельной находки)

  • docs/images/screenshots.json: у всех 10 сценариев imageSha256 не изменился при обновлении sourceFingerprint — подтверждает заявление r1, что правка не задевает ни один заскриншоченный экран (диалог второго маршрута пылесоса нигде не снимается для документации).
  • Приёмка прошла через scripts/docs-accept.mjs (ветка lastWriteWasFingerprintOnly), а не через ручную правку JSON — соответствует требованию §8 «коммит скриншотов делает человек» и «приёмка отказывает, если кандидат снят не с этого дерева»: сам скрипт это проверяет (verifyDocsCandidate), а не декларация автора.
  • docs/reviews/CODE-REVIEW-441-r1.md корректно оформлен как документ своего раунда и не требует правок задним числом (документы ревью не переписываются, только дополняются новым заходом).

Чего не проверял

  • Полный повторный разбор AC1–AC3 по коду и всем смокам — не требуется по §2.10, т.к. дельта не трогает src/**/test/**/demo/**; AC1 дополнительно перепроверен мутацией (см. «Гейты»), AC2/AC3 унаследованы.
  • npm run golden:verify, pytest tests_backend, npm run invariants, performance-профили — не прогонял; обоснование то же, что в r1 (View, backend .py, геометрия/ссылки на неё не затронуты ни fa41d298, ни дельтой r1→r2).
  • node scripts/smoke-select.mjs --base origin/dev --head HEAD по полному диффу — не перегонял: набор символов на изменённых строках не изменился с r1 (дельта не трогает код), решение по каждому пункту из r1 остаётся в силе.
  • Реальность прогона CI-джобы Docs screenshots для коммита 0ea9c0f5 (не видна из репозитория) — доверие основано на структурном доказательстве самого scripts/docs-accept.mjs (совпадение imageSha256 с уже закоммиченными файлами и наличие acceptance.lastWriteWasFingerprintOnly), а не на слепом заявлении автора; независимый пересчёт visualFingerprint(root) на HEAD не делал отдельно от check-docs.mjs, который эту сверку и выполняет.

Вердикт

Зелёный. AC1–AC3 подтверждены (AC1 — независимо на HEAD этой сессией, AC2/AC3 — унаследованы из r1 по неизменному коду), единственная Medium-находка r1 закрыта штатным инструментом и подтверждена зелёным check-docs.mjs на HEAD 75478905. Новых находок нет.

Бюджет циклов (§4): r1 был жёлтым и потратил 1 цикл из 2 (лёгкий/короткий трек, лимит код-ревью — 2, §5.1). Этот заход (r2) зелёный и цикл не образует (#227) — израсходовано остаётся 1 из 2, а не 0 из 2, как было в заголовке этой сессии; расхождение объяснено в разделе «Почему это заход r2».


Материал раунда

  • Ветка: issue/441-vacuum-route-draft, коммит 75478905d5eb — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
  • Дерево материала: 6e2f7f4813e3b45927eb282b1e5fdd62b872d019
    git log --all --format='%H %T' | grep 6e2f7f4813e3