diff --git a/docs/reviews/CODE-REVIEW-520-r3.md b/docs/reviews/CODE-REVIEW-520-r3.md new file mode 100644 index 00000000..2991bc7b --- /dev/null +++ b/docs/reviews/CODE-REVIEW-520-r3.md @@ -0,0 +1,230 @@ +# CODE-REVIEW-520-r3 + +Issue: #520 · Этап: code · Заход: r3 · Материал: `a325294d7a9d8ef4ecfeab2ed3e248318a650ab5` +Вердикт: **зелёный** · High: 0 · Medium: 0 + +## Скоуп + +Третий заход код-ревью после жёлтого r2 (`docs/reviews/CODE-REVIEW-520-r2.md`, +единственная находка Medium-1: `node scripts/check-docs.mjs` красный на материале +ревью — диф трогает `src/houseplan-card.ts` и `src/config-adoption.ts`, что +инвалидирует отпечаток скриншотов документации, а ветка не привезла свой коммит +обновления). + +Дельта r2→r3 — ровно один коммит правки `a325294d` поверх материала r2 +(`462b5645`) плюс публикационный коммит документа r2 (`3066fec1`, без кода): + +``` +$ git diff --stat 462b5645..a325294d + docs/images/screenshots.json | 24 +-- + docs/reviews/CODE-REVIEW-520-r2.md | 358 +++++++++ + 2 files changed, 370 insertions(+), 12 deletions(-) +``` + +Дельта **локальна** в смысле §2.9/§2.10: только `docs/images/screenshots.json` +(класс C, отпечаток + 11 `sourceSha256`), ни одного файла класса A/B, `dist/**` +и `custom_components/houseplan/frontend/**` не тронуты, продуктовый код между +r2 и r3 не менялся вовсе (`git diff 462b5645..a325294d -- src test scripts +custom_components` — пусто). Разбор в этом раунде сужен до дельты и до находки +r2 — остальное наследуется из r2 без повторной проверки (раздел ниже). + +## Как проверялось + +1. Найден вердикт предыдущего раунда (комментарий issue #11, 2026-09-10 + 17:47:34) и материал, на котором он получен: `462b56453cd6948c083e62ad8c92ec29aeb022b2`, + зафиксирован в `docs/reviews/CODE-REVIEW-520-r2.md` блоком «Материал раунда». + `git diff 462b5645..a325294d` — предмет этого раунда (см. «Скоуп»). +2. По единственной находке r2 показано, чем именно она закрыта — не заявлением + автора: `git diff 462b5645..a325294d -- docs/images/screenshots.json` + меняет ровно `sourceFingerprint` и 11 полей `sourceSha256` + (`ccbbfb4e5aa1… → c615d58061456…`), ни один `imageSha256` не изменился — + то есть ни один PNG не поменялся, менялся только отпечаток источников. + Прогнал сам: + ``` + $ node scripts/check-docs.mjs + Documentation checks passed (7 files, 12 external links). + ``` + Красный до фикса зафиксирован в документе r2 буквальным выводом той же + команды («ERROR screenshot source fingerprint is stale…») — «умеет падать» + доказано предыдущим раундом, здесь показан переход в зелёное на исправленном + материале. +3. Трейлеры коммита `a325294d`: `Issue: #520`, `User-Visible: no` — корректно, + диф не меняет ничего, что видит пользователь дома (только служебный + отпечаток документации); changelog не тронут — соответствует. +4. `dist/**` и `custom_components/houseplan/frontend/**` не входят в диф этого + коммита (`git show --stat a325294d`) — ожидаемо для чисто документационной + правки; сверил, что три копии бандла всё ещё совпадают побайтово: + `cmp dist/houseplan-card.js custom_components/houseplan/frontend/houseplan-card.js` + — молча (совпадают). +5. `node scripts/process-gate.mjs` на диапазоне `origin/dev..HEAD` — «гейт + пройден, предупреждений 2» (те же WARN про `node_modules` вне классов + A/B/C/D на исторических коммитах `37ef970d`/`e181b08f`, уже закрыты и + разобраны в r1/r2 как гигиена ветки, не влияющая на финальное дерево). +6. Дешёвые гейты (`typecheck`, `npm test`, `npm run build` со сверкой копий + бандла) на точном материале `a325294d` подтверждены зелёным Validate: + https://github.com/Matysh/houseplan-card/actions/runs/34513504274 + (`headSha` сверен через `gh run view --json headSha` — совпадает с + материалом раунда). Не перегонял третьей парой глаз — принято по инструкции + ревью, это не новый код с прошлого раунда (продуктовый код между r2 и r3 + не менялся). +7. **Тело issue менялось повторно после r2.** Ревью r2 уже зафиксировало + расхождение с записанным хешем SPEC-REVIEW-520-r3 (#517: `60492a3aec5f…` + против тогдашнего `4524f04412...`). Между вердиктом r2 (17:47:34) и + материалом r3 тело изменилось **ещё раз** — автор сам называет это в + хендоффе (комментарий issue #12): добавлены AC7 и пункт риска про отпечаток + скриншотов, по прямому требованию находки Medium-1 r2. Текущий хеш тела: + `sha256sum` по тексту, полученному `gh issue view 520 --json body -q .body` + → `f318b25f5815fa66aeaa7cbc5ce1d63e23fab0a8e50493962634b01e0ca86e96` — + отличается от обоих предыдущих записанных значений. Сверено построчно: + правка аддитивна — AC1–AC6, «Причина», «Контракт», «Риски» (кроме одного + нового пункта) не тронуты; новый AC7 («`check-docs` зелёный на материале + ревью») и новый риск-пункт об отпечатке скриншотов дословно описывают + именно то, что закрывает коммит `a325294d`, и ничего сверх этого. Новых + продуктовых развилок текст не вводит, `User-Visible: no` не меняется. + Возврата в `S4-spec-review` не требую — та же логика, что применил r2 к + первому расхождению (дисциплинированное обновление ТЗ вслед за находкой + кода, не смена скоупа). + +## Закрытие раунда r2 + +| Находка r2 | Чем закрыта | Где это видно | +|---|---|---| +| Medium-1 — `node scripts/check-docs.mjs` красный на материале ревью: отпечаток скриншотов документации устарел (диф трогает `src/houseplan-card.ts`, `src/config-adoption.ts`) | Коммит `a325294d`: отпечаток обновлён через `npm run docs:accept -- --identical` (#512) — все 11 кадров пересняты и совпали с закоммиченными побайтово (ни один `imageSha256` не изменился), обновился только `sourceFingerprint` и 11 `sourceSha256` | Прогнал `node scripts/check-docs.mjs` на материале `a325294d` сам — «Documentation checks passed (7 files, 12 external links)»; `git diff 462b5645..a325294d -- docs/images/screenshots.json` показывает ровно 12 изменённых полей, ноль изменённых `imageSha256` | + +Находка r2 закрыта полностью и минимально — правка не расширилась за пределы +её предмета. + +## Унаследовано из r2 (без повторной проверки) + +Продуктовый код между материалом r2 (`462b5645`) и материалом r3 (`a325294d`) +не менялся — дельта чисто документационная (см. «Скоуп»), поэтому из +`docs/reviews/CODE-REVIEW-520-r2.md` наследуется всё содержательное: + +- **Находка r1 (High) и её закрытие.** Механизм регрессии (микрозадача после + `await` в `adoptAuthoritativeGated`, а не Lit `wrapped`) и хук `afterAdopt` — + r2 перепроверил независимым измерением на изолированном `git worktree` + (база `a44fbd37` vs `462b5645`), оба профиля (`interaction`, `isometric`), + `benchmark:compare` — все строки бюджета зелёные. Код с тех пор не менялся, + повторное измерение в этом раунде избыточно. +- **AC1, AC2, AC6** — тесты и все четыре мутанта (`adoption-bodies-declared-reactive`, + `adoption-notifies-no-host-on-config-replacement`, `adoption-tail-defers-caller-hook`, + `authoritative-load-seeds-devices-after-the-await`) перепрогнаны r2 лично, + «поймано 1 из 1» каждый; код, которого это касается, в дельте r2→r3 + отсутствует. +- **AC3, AC4, AC5** — измерены r2 независимо (не на слово автора): 18 циклов / + 3 сборки / 3 эпохи на обоих деревьях и обоих профилях, `benchmark:compare` + — 0 красных строк, `cache.entries.cleanFloor` 100 (interaction) / 60 + (isometric). Перф-путь этой дельтой не задет. +- **Бюджет бандла** (потолок 300 300 → 300 400, +40 Б) и `test/bundle-assets.test.mjs` + (26/26 pass) — не тронуты дельтой. +- **17 из 17 «прямых совпадений» `smoke-select`** плюс 3 названных автором + сверх выборки — прогнаны r2 лично, все `OK`; исходный код, который они + проверяют, в этой дельте не менялся. +- **Гигиена ветки** (симлинк `node_modules`, исправление `.gitignore`) — + зафиксирована в r1, не менялась. +- **Первое расхождение тела issue с хешем SPEC-REVIEW-520-r3** (#517) — + разобрано r2, решение «возврата в spec не требую» подтверждено тем же + рассуждением и в этом раунде (см. п.7 «Как проверялось» — уже про второе, + новое расхождение). +- **Откат** — «один revert» из ТЗ технически устарел (теперь три файла, не + один), это отмечено уже r2 как факт вне AC; не предмет этого раунда. + +Материал: `docs/reviews/CODE-REVIEW-520-r2.md`, SHA `462b56453cd6948c083e62ad8c92ec29aeb022b2`. + +## Что проверено и корректно + +- **AC7** (новый в теле issue, добавлен вслед за находкой Medium-1 r2) — + `node scripts/check-docs.mjs` зелёный на материале `a325294d`, прогнан + лично: «Documentation checks passed (7 files, 12 external links)». + «Чем краснеет» — устаревший `sourceFingerprint`, продемонстрировано самим + переходом красный (документ r2) → зелёный (этот документ) на одном и том же + коде отпечатка. +- Ни один `imageSha256` не изменился в диффе r2→r3 — визуальный контент + скриншотов не менялся, обновление чисто механическое (отпечаток источников). +- Три копии бандла (`dist/houseplan-card.js`, + `custom_components/houseplan/frontend/houseplan-card.js`, стендовая не + коммитится) совпадают побайтово — сверено `cmp`. +- Трейлеры `a325294d` — `Issue: #520`, `User-Visible: no`, корректно для + чисто документационной правки. +- `node scripts/process-gate.mjs` — гейт пройден, предупреждения те же, что + и в r1/r2 (гигиена исторических коммитов, не влияет на финальное дерево). +- Validate зелёный на точном материале раунда (`headSha` сверен явно, не + принят на слово) — typecheck/test/build подтверждены этим прогоном. +- Второе расхождение тела issue с записанным хешем ревью ТЗ — названо, + разобрано построчно (аддитивно, соответствует коммиту `a325294d`), решение + «без возврата в spec» обосновано. + +## Чего не проверял + +- **`npx tsc --noEmit`, `npm test` (весь набор), `npm run build` третьим + прогоном** — Validate зелёный на точном материале `a325294d` + (headSha сверен), продуктовый код между r2 и r3 не менялся; перегон дал бы + тот же результат, что уже подтверждён r2 и Validate. +- **Полное измерение перф-профилей (`benchmark:compare`)** — не перегонял: код + пути загрузки не менялся между r2 и r3, r2 уже воспроизвёл результат + независимо на изолированном `git worktree`, эта дельта его не касается. +- **Смоки `demo/smoke_*.mjs`** — не перегонял ни одного: диф r2→r3 не + затрагивает `src/**`/`demo/**`, `smoke-select` на этой дельте не даёт ни + одного совпадения (проверил: диф ограничен `docs/**`, инструмент по + символам кода не находит кандидатов). +- **`npm run golden:verify`** — не запускал: диф не меняет рендер ни байтом, + визуальная приёмка `--identical` уже доказала попиксельное совпадение всех + 11 кадров с закоммиченными PNG. +- **`npm run invariants`, `python -m pytest tests_backend`** — geometry и + Python-бэкенд этой дельтой не затронуты (не были затронуты и всей веткой, + подтверждено r2). + +## Гейты: что прогнал сам и почему + +| Гейт | Прогнан | Результат | +|---|---|---| +| `node scripts/check-docs.mjs` | да (предмет находки r2, обязателен) | зелёный: «Documentation checks passed (7 files, 12 external links)» | +| `git diff 462b5645..a325294d` (полный, не только имена файлов) | да | 2 файла: отпечаток + публикационный документ r2 | +| `cmp dist/houseplan-card.js custom_components/houseplan/frontend/houseplan-card.js` | да | совпадают побайтово | +| `node scripts/process-gate.mjs` | да | пройден, 2 предупреждения (унаследованы, не новые) | +| `gh run view 34513504274 --json headSha,conclusion` | да | `headSha` = материал раунда, `conclusion: success` | +| `sha256sum` тела issue | да | отличается от обеих предыдущих записей — находка по #517, разобрана в тексте (не блокирует) | +| `npx tsc --noEmit`, `npm test`, `npm run build` (свежий прогон) | нет | Validate зелёный на точном SHA, продуктовый код с r2 не менялся | +| Perf `benchmark:compare` (оба профиля) | нет | код пути загрузки не менялся с r2, где уже измерено независимо | +| `demo/smoke_*.mjs` | нет | дельта не касается `src/**`/`demo/**`, кандидатов ноль | +| `npm run golden:verify` | нет | визуальный контент не менялся, доказано `--identical` | +| `npm run invariants`, `pytest tests_backend` | нет | geometry/backend вне диапазона всей ветки | + +## Вердикт + +Зелёный. High: 0, Medium: 0. Единственная находка r2 (Medium-1, `check-docs` +красный из-за устаревшего отпечатка скриншотов) закрыта минимальной и точной +правкой — один файл, только отпечаток, ни одного изменённого PNG; перепроверено +прямым прогоном гейта на материале раунда, не на слово автора. Продуктовый код +не менялся с r2, чья находка High (регрессия первого кадра) и все AC1–AC6 уже +были независимо перепроверены измерением и остаются в силе. Новое, второе +расхождение тела issue с зафиксированным хешем ревью ТЗ (#517) названо и +разобрано — аддитивно, соответствует коду, возврата в spec не требует. Задача +готова к пре-релизной очереди. + +--- + +## Материал раунда + +- Ветка: `issue/520-first-frame`, коммит `a325294d7a9d8ef4ecfeab2ed3e248318a650ab5`. +- Родитель материала r2: `462b56453cd6948c083e62ad8c92ec29aeb022b2` (`docs/reviews/CODE-REVIEW-520-r2.md`). +- Тело issue на момент ревью: sha256 `f318b25f5815fa66aeaa7cbc5ce1d63e23fab0a8e50493962634b01e0ca86e96` + (получено `gh issue view 520 --json body -q .body | sha256sum`), отличается от + записанного в SPEC-REVIEW-520-r3 (`60492a3aec5f…`) и от значения, названного + в CODE-REVIEW-520-r2 (`4524f04412...`) — разобрано в тексте, возврата в spec + не требует. +- Вердикт этого документа: зелёный · High 0 · Medium 0 + +--- + + + +## Материал раунда + +- Ветка: `issue/520-first-frame`, коммит `a325294d7a9d` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. +- Дерево материала: `f7b30b932911c9f15765594194a6a0b7852d9f1c` + ``` + git log --all --format='%H %T' | grep f7b30b932911 + ``` +- Тело issue: `80073dd20133cdbba0bc717c7996f490c2d9010734fecedc11fcf8f894190143` +- Вердикт конвейера: `green` · High 0