diff --git a/docs/reviews/CODE-REVIEW-329-r3.md b/docs/reviews/CODE-REVIEW-329-r3.md new file mode 100644 index 00000000..5dd59f19 --- /dev/null +++ b/docs/reviews/CODE-REVIEW-329-r3.md @@ -0,0 +1,157 @@ +# CODE-REVIEW-329-r3 + +Этап: code · заход r3 · блокирующих циклов израсходовано 2 из 4 + +## Скоуп раунда + +Предыдущий вердикт (code r2, `226`-й комментарий issue) — красный, +единственная находка **r2-H1**: мутант `junction-limit-backend-raw-baseline` +в `scripts/mutation-gate.mjs` был добавлен с `guard: 'python3 -m pytest +tests_backend/test_junction_limits.py -q'`, в обход конвенции ВСЕХ прочих +бэкенд-мутантов реестра (`node scripts/backend-test-guard.mjs +`), из-за чего `test/mutation-gate.test.mjs` красился на CI. + +Вердикт r2 получен на SHA `26c6e870` (Matysh: «Актуальный HEAD ветки для +ревью — `26c6e870`», непосредственно перед вердиктом). Автор закрыл +находку коммитом `273b0d5e`, текущий HEAD. + +Дельта этого раунда: + +``` +git diff 26c6e870..HEAD --stat (без docs/reviews/*) + scripts/mutation-gate.mjs | 4 ++-- + test/mutation-gate.test.mjs | 6 +----- + 2 files changed, 3 insertions(+), 7 deletions(-) +``` + +Дельта не затрагивает `src/**`, бэкенд-продакшен-код, геометрию, документацию +пользователя — только реестр мутантов и его контрактный тест. Это ровно то, +что запрошено находкой r2-H1, без побочных правок. Разбор по дельте признан +достаточным: изменение локально, не является ребейзом, не меняет контракт +поведения продукта и по объёму несопоставимо мало относительно исходной +задачи (две строки правки guard + возврат теста к исходному виду). + +## Что проверено (дельта) + +1. **Форма guard соответствует конвенции.** Новый guard — + `node scripts/backend-test-guard.mjs + test_legacy_baseline_is_judged_after_the_same_migration + tests_backend/test_junction_limits.py` — совпадает по форме со всеми + остальными записями реестра, использующими бэкенд-хелпер (проверено + `grep -n "backend-test-guard" scripts/mutation-gate.mjs` — 16 вхождений, + новое неотличимо от прочих). +2. **Контракт теста возвращён к исходному виду.** + `test/mutation-gate.test.mjs` снова требует, чтобы guard называл `.mjs` + (убрана временная ветка `.py`, убран комментарий-объяснение, который её + оправдывал). `grep` подтвердил: других мутантов, называющих `.py` + напрямую (в обход хелпера), в реестре нет — правка не откроет дыру для + будущих аналогичных случаев. +3. **Мутант по-прежнему ловит регрессию.** Прогнан НЕ ТОЛЬКО `--check` + (проверяет только уникальность якоря патча), а полный цикл конкретного + мутанта: + `node scripts/mutation-gate.mjs --id=junction-limit-backend-raw-baseline` + → + ``` + ok чистый прогон: node scripts/backend-test-guard.mjs test_legacy_baseline_is_judged_after_the_same_migration tests_backend/test_junction_limits.py + ok junction-limit-backend-raw-baseline: тест покраснел, как обязан + поймано 1 из 1 + ``` + То есть подтверждено обеими половинами: код без мутации проходит целевой + тест, а с применённым патчем (`migrated = config` вместо прогона через + `commit_wall_segment_model`) целевой тест красится. Это и есть доказательство + «тест умеет падать» для данной находки. +4. **pytest напрямую.** `python3 -m pytest tests_backend/test_junction_limits.py -q` + → `8 passed`. (pytest в песочнице ревью отсутствовал изначально, установлен + `pip3 install --user pytest` — тот же шаг, что r2 констатировал как разовую + особенность окружения, не продукта.) +5. **`npm test`** → `# tests 1391 / # pass 1390 / # fail 0 / # skipped 1`, + совпадает с итогом, который автор указал в коммите `273b0d5e`. +6. **`npx tsc --noEmit`** — чисто (дельта не трогает `.ts`, но прогнан по + правилу «всегда»). +7. **`npm run build`** — собрался, `dist/houseplan-card.js` создан. + Сверка бандла: `cmp dist/houseplan-card.js + custom_components/houseplan/frontend/houseplan-card.js` — совпадает + побайтово. Третья копия, `demo/srv/assets/houseplan-card.js`, в дереве + отсутствует (она untracked рабочая копия demo-стенда, `bundle-sync.mjs` + создаёт её по требованию) — отсутствие ожидаемо и не связано с этой + правкой, дельта фронтенд не трогает. +8. **`node scripts/check-docs.mjs`** → `Documentation checks passed (7 files, + 10 external links)`. Формально необязателен (дельта не в `src/**`), прогнан + по инерции — зелёный. +9. **`node scripts/smoke-select.mjs --base 26c6e870 --head HEAD`** → + «Исполняемого frontend-диффа нет (`src/**/*.ts` не тронут). Browser-smoke + этим диффом не выбираются — выбирать нечего». Полный прогон смоков не + делал — инструмент прямо говорит, что выбирать нечего, а не «неопределённость». + +## Закрытие раунда r2 + +| Находка | Чем закрыта | Где это видно | +|---|---|---| +| r2-H1: guard бэкенд-мутанта в обход конвенции `.mjs`-хелпера, контрактный тест красный на CI | `scripts/mutation-gate.mjs`: guard мутанта `junction-limit-backend-raw-baseline` переписан на `node scripts/backend-test-guard.mjs test_legacy_baseline_is_judged_after_the_same_migration tests_backend/test_junction_limits.py`; `test/mutation-gate.test.mjs`: контракт `every guard command points at a file that exists` возвращён к проверке только `.mjs`, временная ветка для `.py` и оправдывающий её комментарий убраны | Коммит `273b0d5e`; `npm test` 1390/0 (было 1389 passed/1 failed на `0824e510`); точечный прогон `node scripts/mutation-gate.mjs --id=junction-limit-backend-raw-baseline` — «поймано 1 из 1» | + +## Унаследовано из r2 (и, транзитивно, из r1) + +Без повторной проверки исполнением приняты — дельта r3 их не касается кодом, +которого они доказывают: + +- **H1 (бэкенд мигрирует обе стороны перед сравнением)** — доказано в r1, + подтверждено закрытым в r2 тестом `test_legacy_baseline_is_judged_after_the_same_migration` + и мутантом. Документ: `docs/reviews/CODE-REVIEW-329-r2.md`, раздел + «Закрытие раунда r1», SHA `26c6e870`. +- **M1 (мёртвый код `apexCaps`/`clipPolygonOutsideCap`/`degenerateApexCaps` + удалён)** — `docs/reviews/CODE-REVIEW-329-r2.md`, SHA `26c6e870`. +- **M2/M3 (дубль раздела USER-GUIDE устранён, канал Resize описан верно)** — + там же, SHA `26c6e870`. +- **M4 (AC10, Optimize не создаёт новых нарушений, доказан двумя юнитами)** — + там же, SHA `26c6e870`. +- **Остальные AC (П1–П5 юниты и границы, §4 честная вершина + golden, AC5a/b, + AC7a через реальный pointer-жест, AC7b, паритет AC9, скоуп применения AC8)** — + впервые проверены и признаны корректными в `docs/reviews/CODE-REVIEW-329-r1.md`, + подтверждены неизменными в r2 (дельта r1→r2 их не трогала за вычетом + перечисленных выше M1–M4 и H1); дельта r2→r3 тем более их не трогает + (единственные изменённые файлы — `scripts/mutation-gate.mjs` и + `test/mutation-gate.test.mjs`, не пересекающиеся с производственным кодом + junction-limits, рендером или бэкендом). Документ: `docs/reviews/CODE-REVIEW-329-r1.md`, + SHA `e1df015d`; golden/invariants/мутанты для этих AC — из отчёта r1 + («что прогнано»). +- **Полный HA-harness backend не прогоняется** — унаследованный пробел + окружения, констатирован ещё в r1 (недоступны `homeassistant`/`voluptuous`), + подтверждён в r2, в r3 не переоценивался — дельта его не касается. + +## Чего не проверял в этом раунде и почему + +- **`npm run golden:verify`** — не прогонял. Дельта не трогает рендер, + геометрию, стили, слои; полная матрица (~80 сцен) уже прогнана и зелёная + в r2 на коде, который в r3 не менялся. +- **`npm run invariants`** — не прогонял. Дельта не трогает рёбра комнат, + записи толщины, `layout`, `marker.space`, `open_spans` — инварианты модели + здесь неприменимы. +- **Браузерные смоки** — не прогонял ни одного. `smoke-select.mjs` для + диапазона `26c6e870..HEAD` прямо сообщает «выбирать нечего»: единственные + изменённые файлы — `scripts/mutation-gate.mjs` и `test/mutation-gate.test.mjs`, + оба вне `src/**`, ни один смок такой диапазон не оценивает даже как слабую + связь. +- **`python -m pytest tests_backend -q` (полный набор)** — прогнал только + файл `test_junction_limits.py`, целевой для находки; полный бэкенд-набор + не запускал, так как дельта не трогает бэкенд-продакшен-код (только тест + и реестр мутантов на фронтенде/CI), а `test_junction_limits.py` — тот файл, + контракт которого проверяет закрытие r2-H1. +- **Performance-профили** — не прогонял, в AC не названы и дельта их не + задевает. +- **Полный `.github/workflows/mutation-gate.yml` (пересборка бандла на + каждого мутанта)** — не прогонял; это предрелизный гейт (PROCESS.md §8), + несоразмерен точечной правке одной записи реестра. Точечный прогон именно + этого мутанта сделан отдельно (см. выше) и достаточен как доказательство. + +## Вывод + +Единственная находка r2 (High) закрыта по существу и подтверждена +исполнением: guard мутанта следует конвенции, контракт реестра не ослаблен, +мутант по-прежнему доказанно ловит регрессию H1 (1/1), `npm test` и +`pytest tests_backend/test_junction_limits.py` зелёные. Новых находок delta +не создаёт — правка изолирована в тестовой инфраструктуре, не пересекается +с продакшен-кодом или пользовательским поведением. Trailer коммита +(`Issue: #329`, `User-Visible: no`) корректен для чисто тестового изменения; +changelog не тронут — верно, правок не требовалось. + +Вердикт: зелёный.