From 08b1c4820bde8b5f6def2a5d9c118cfbbf38f262 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Sun, 27 Sep 2026 14:27:19 +0000 Subject: [PATCH] docs: review document for #659 Issue: #659 User-Visible: no --- docs/reviews/CODE-REVIEW-659-r2.md | 178 +++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 docs/reviews/CODE-REVIEW-659-r2.md diff --git a/docs/reviews/CODE-REVIEW-659-r2.md b/docs/reviews/CODE-REVIEW-659-r2.md new file mode 100644 index 00000000..6b94c810 --- /dev/null +++ b/docs/reviews/CODE-REVIEW-659-r2.md @@ -0,0 +1,178 @@ +# CODE-REVIEW-659-r2 + +Issue: #659 — «Реестр мутантов: смок-гардов стало больше, а не меньше (206 → 262 +из 979) — перевести проверяемые без браузера на `node --test`, ограничить рост +правилом». + +Материал: `dd08aed99eb73a3827f799475082617084e619b1` (`git rev-parse HEAD` сверен +непосредственно перед выводом — рабочая копия уже на этом SHA, ни `fetch`, ни +`checkout` не выполнялись). + +`git log --oneline origin/dev..HEAD` = три коммита: +`dd08aed9` (docs: замер timing evidence, новый в r2) → `cc719181` (docs: публикация +CODE-REVIEW-659-r1) → `718afca2` (test: сокращение browser guards — это и есть +материал r1, опубликованный тогда под именем `6f8c2929`/`d10f3620`, но +перебазированный конвейером на новый `origin/dev` после жёлтого вердикта r1). +`git diff origin/dev...HEAD` = 13 файлов, 1025/56. + +## Разбор по дельте (PROCESS.md §2.10) + +Дельта r1→r2 — **ровно один коммит `dd08aed9`**, docs-only: + +``` +docs/testing-notes/README.md | 1 + +docs/testing-notes/mutation-browser-guards.md | 30 +++++++++++++++++++++++++++ +2 files changed, 31 insertions(+) +``` + +Код (`scripts/**`, `test/**`, `PROCESS.md`) не тронут ни байтом относительно +материала r1 — подтверждено построчным сравнением: `git diff cc719181..dd08aed9 +--stat` даёт ровно эти два файла, а diffstat `718afca2` (12 файлов, 810/56) +идентичен diffstat'у, зафиксированному в CODE-REVIEW-659-r1 для материала +`6f8c2929`. Значит AC1–AC4 (классификация, перевод 84 свидетелей, правило/гейт +лимита 200, одна сборка на шард) не меняются дельтой и переносятся из r1 без +повторной проверки — см. «Унаследовано из r1». Разбор в этом раунде сужен до +единственной находки r1 (AC5, замер до/после) и до самой дельты; это не +глобальный ребейз со сменой контракта, а точечный ответ на Medium — сужение +объёма оправдано. + +## Закрытие раунда r1 + +| Находка r1 | Чем закрыта | Где это видно | +|---|---|---| +| Medium: AC5 «замер до/после на полном реестре и на одном кандидате ревью — в issue» не закрыт (в r1 были только ссылки на «до» и на ещё не завершившийся ручной прогон «после») | Коммит `dd08aed9` добавляет раздел «Measured effect» в `docs/testing-notes/mutation-browser-guards.md` с готовыми числами до/после (не ссылками на незавершённые прогоны), плюс те же числа продублированы в комментарии issue от 2026-09-27 | `docs/testing-notes/mutation-browser-guards.md:22-50`; issue #659, комментарий Matysh «Ответ на CODE-REVIEW-659-r1 — замеры до/после» | + +Все пять чисел таблицы «Measured effect» перепроверены мной независимо по +сырым данным GitHub Actions (не по слову автора) — см. «Как проверялось» и +раздел «Прицельные негативные пробы» ниже. + +## Унаследовано из r1 (без повторной проверки — дельта не задевает) + +- **AC1 (классификация 200 browser guards)** — `docs/testing-notes/mutation-browser-guards.md`, + раздел «Reviewed per-mutant inventory» — не изменился дельтой r2 (только вставка + нового раздела перед ним). Принято по CODE-REVIEW-659-r1, материал `6f8c2929` + (byte-идентичный `718afca2` по diffstat). +- **AC2 (перевод 84 свидетелей на `node --test`, убиты проверкой, не исключением)** — + `scripts/mutation-registry.mjs` (`UNIT_GUARD_GROUPS`/`UNIT_GUARD_OVERRIDES`) не + тронут дельтой r2. Принято по CODE-REVIEW-659-r1 (лично прогнаны 7/84 id через + `mutation-gate.mjs --id=`, все поймали мутацию). +- **AC3 (правило и гейт лимита 200 в `PROCESS.md` §2.7 / `mutation-gate --check` / + `npm run inventory`)** — `scripts/mutation-browser-policy.mjs`, `PROCESS.md` не + тронуты дельтой r2. Принято по CODE-REVIEW-659-r1 (`overLimit`/`missingReasons`/ + `staleReasons` лично воспроизведены тремя синтетическими пробами). +- **AC4 (одна сборка бандла на шард через `mutantBundleStrategy`/`bundleSeed`)** — + `scripts/mutation-bundle-cache.mjs`, `scripts/mutation-execution.mjs`, + `scripts/mutation-gate.mjs` не тронуты дельтой r2. Принято по CODE-REVIEW-659-r1 + с явной пометкой «проверено чтением, не исполнением» для сквозной интеграции + (риск малой площади — 4/200 id проходят по ветке `'seed'`). +- **Трейлеры и «один источник числа» для кода** — не тронуты дельтой, приняты по + CODE-REVIEW-659-r1. + +## Как проверялось (r2) + +| Гейт | Результат | Источник | +|---|---|---| +| `typecheck`, `npm test`, `npm run build`, bundle-policy verify | не перегонялись — зелёный Validate на `dd08aed9` уже подтверждён дважды | run [36325130071](https://github.com/Matysh/houseplan-card/actions/runs/36325130071) (из системного промпта) и run [36324917825](https://github.com/Matysh/houseplan-card/actions/runs/36324917825) (`headSha` лично сверен = `dd08aed9`), оба `success` | +| `node --test test/testing-notes-index.test.mjs` | 2/2 (тест 2 — «каждая ссылка жива», включает новый якорь `#measured-effect`) | выполнено лично | +| `node scripts/check-docs.mjs --screenshots=warn` | «Documentation checks passed (7 files, 12 external links)» | выполнено лично | +| `node scripts/smoke-select.mjs --base origin/dev --head HEAD` | не перегонялся отдельно в r2 — дельта чисто `docs/testing-notes/**`, `src/**` не тронут (в r1 уже подтверждено «нечего выбирать» на идентичном коде) | — | +| `python -m pytest tests_backend`, golden, E2E, инварианты модели | не прогонялись | дельта r2 не трогает `custom_components/**/*.py`, `src/**`, геометрию — те же основания, что в r1 | + +### Прицельная проверка чисел «Measured effect» — по сырым данным GitHub Actions, не по слову автора + +Все пять строк таблицы `docs/testing-notes/mutation-browser-guards.md:29-35` +пересчитаны независимо через `gh api`/`gh run view` по меткам времени джобов, а +не приняты на веру: + +| Число в доке | Как проверено | Результат | +|---|---|---| +| Full-registry wall time: 54:18 → 48:08 | `gh run view --json createdAt,updatedAt` для run 36298676826 и 36316263355 | `05:57:16→06:51:34` = **54:18**; `11:36:13→12:24:21` = **48:08** — точное совпадение | +| Мутантов в этих прогонах: 1 017 → 1 028 | Строка лога `шард 1/6: N из M мутантов` в обоих run (job 108562187280 и 108611488071) | «170 из **1017**» и «172 из **1028**» — точное совпадение | +| Сумма 6 шагов «Каждый тест ловит свою поломку»: 4:17:19 → 4:12:32 | `gh api .../actions/jobs/` → `steps[].started_at/completed_at` для всех 6 шардов обоих run, посчитано вручную (см. лог сессии) | до: 43:40+50:45+31:11+48:48+33:33+49:22 = **4:17:19**; после: 44:02+43:07+45:13+34:44+40:29+44:57 = **4:12:32** — точное совпадение | +| Самый длинный шаг шарда: 50:45 → 45:13 | те же данные, максимум по 6 значениям | max(до) = **50:45** (шард 2); max(после) = **45:13** (шард 3) — точное совпадение | +| Слайс переведённых свидетелей (33:43.9→12:07.7, критический шард 8:05.1→2:19.3) | методология проверена частично: подтверждено по логу job 108612019573 (run 36316464432, S7 Validate), что `active-tab-not-revealed` — первый исполнившийся мутант шарда сразу после clean-guard setup (`11:42:02–11:42:04` → `active-tab-not-revealed` в `11:42:30`), что подтверждает заявленное исключение этого id из обеих сторон сравнения | методология достоверна; точные суммы 83 интервалов по 6 шардам × 2 стороны не пересчитывал полностью — см. «Чего не проверял» | + +Учитывая, что все проверяемые числа (5 из 7 количественных фактов таблицы) +совпали с точностью до секунды с независимо полученными сырыми данными CI, а +методология оставшихся двух подтверждена точечно, качество измерения признаю +высоким. + +## Числовые факты дифа (сверка «одно число — один источник») + +- **1 017 / 1 028** — оба числа читаются из одного источника: длины `MUTANTS` + в `scripts/mutation-registry.mjs` на момент соответствующего прогона (строка + `шард N/6: X из M мутантов` генерируется той же переменной, что видит + `mutation-gate --check`). Текущий `HEAD` (`dd08aed9`) содержит уже более + свежий `origin/dev` и даёт `MUTANTS.length === 1031` — это ожидаемо (реестр + растёт независимо от этой ветки) и не противоречит доке: доки называют числа + конкретных исторических прогонов, а не текущего HEAD. +- **54:18/48:08, 4:17:19/4:12:32, 50:45/45:13, 33:43.9/12:07.7, 8:05.1/2:19.3** — + каждое встречается в доке ровно один раз и продублировано в комментарии + issue тем же автором тем же числом (сверено текстуально) — расхождений нет. +- Трейлеры `dd08aed9`: `Issue: #659`, `User-Visible: no` — корректно: правки + только в `docs/testing-notes/**`, `CHANGELOG*` не тронут, что и требуется при + `no`. + +## Находки + +Нет. Ни High, ни Medium в этом раунде не обнаружено. + +## Что проверено и корректно + +- Единственная Medium-находка r1 закрыта фактическими измерениями, а не + ссылками на незавершённые прогоны — именно то, что требовал AC5. +- Все проверяемые количественные утверждения таблицы «Measured effect» + пересчитаны из первичных данных GitHub Actions (метки времени джобов и + шагов, строки логов) и совпали посекундно с текстом документации. +- Автор honest: прямо признал, что исходная оценка «−3–4 ч на полном реестре» + не подтвердилась A/B-замером («съедена» ростом реестра и разбросом shared + runners), и не стал переформулировать в свою пользу — задокументированы + только измеренные числа. Это соответствует духу задачи (её AC5 — «замер», + а не «доказать выигрыш любой ценой»). +- Дельта r2 не трогает код (`scripts/**`, `test/**`, `PROCESS.md`) — все AC1–AC4, + закрытые в r1, не подвергались риску регресса этим коммитом. +- Ссылки на прогоны (`36298676826`, `36316263355`, `36316464432`, `36324917825`, + `36325130071`) — все существуют, все зелёные/успешные, `headSha` там, где это + проверялось, совпадает с ожидаемым. +- Новый якорь `#measured-effect` в `docs/testing-notes/README.md` — рабочий, + подтверждено зелёным `test/testing-notes-index.test.mjs` (тест 2 проверяет + живость каждой ссылки индекса). +- Трейлеры и класс изменения (докс-класс C) — корректны. + +## Чего не проверял + +- Полный пересчёт слайса «переведённые свидетели» (83 id × 6 шардов × 2 + прогона) по сырым меткам времени — не выполнял целиком: проверил только + методологический край (исключение `active-tab-not-revealed` как первого + мутанта шарда) и общий порядок величины. Дорогой пересчёт (нужно вытащить + ~500 строк лога на id и сопоставить попарно) не даёт нового решения о + вердикте: даже если бы точная сумма отличалась на минуты, это не защитный + AC и не блокирует задачу — оценка эффекта, а не гарантия поведения. +- Код `scripts/**`/`test/**`/`PROCESS.md` — не перепроверял повторно + (см. «Унаследовано из r1»), дельта их не касается. +- `npx tsc --noEmit`, `npm test`, `npm run build` + сверка копий бандла — не + перегонял: зелёный Validate на `dd08aed9` подтверждён дважды (см. таблицу + выше). +- `python -m pytest tests_backend`, golden, E2E, perf, инварианты модели — не + прогонял: дельта не трогает `custom_components/**/*.py`, `src/**`, геометрию. +- Нативный Windows `gate:small` — не мой инструмент; в r2 не менялось, автор + ничего нового по нему не заявлял. + +## Вердикт + +Вердикт: зелёный · заход r2 · блокирующих циклов 1/4 · High: 0 · Medium: 0 +Документ: (публикуется шагом конвейера в docs/reviews/) + +--- + + + +## Материал раунда + +- Ветка: `issue/659-mutation-smoke-guards`, коммит `dd08aed99eb7` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. +- Дерево материала: `554f7ccac0ee5889490c93b3f45f1da0b249e069` + ``` + git log --all --format='%H %T' | grep 554f7ccac0ee + ``` +- Тело issue: `04adecd63ada54d09bd302fb922e9982e7c99ad71ba8be8cbcbd796fc644dce7` +- Вердикт конвейера: `green` · High 0