diff --git a/docs/reviews/CODE-REVIEW-553-r3.md b/docs/reviews/CODE-REVIEW-553-r3.md new file mode 100644 index 00000000..067255d5 --- /dev/null +++ b/docs/reviews/CODE-REVIEW-553-r3.md @@ -0,0 +1,168 @@ +# CODE-REVIEW-553-r3 + +Issue: #553 · заход r3 · блокирующих циклов израсходовано 2 из 4 +Материал: `f601182a908b5b30a302f122c89265cbf933474c` (ветка `issue/553-process-doc-canonicalization`), рабочая копия уже на нём; `git fetch`/`pull`/`checkout` на другой коммит не выполнялись. + +## Почему разбор по дельте, а не заново + +Между r2 (`55db3d49`) и r3 (`f601182a`) нет ребейза и нет смены контракта поведения: +`git log origin/dev..HEAD` показывает те же коммиты r2 плюс два новых сверху +(`cc664740` — публикация документа CODE-REVIEW-553-r2, `f601182a` — правка +теста). Дельта равна ровно `git diff 55db3d49..f601182a`: + +``` +docs/reviews/CODE-REVIEW-553-r2.md | 197 +++++++++++++++++++++++++++++++++++++ +scripts/mutation-gate.mjs | 13 +++++++++++++ +test/review-doc-guard.test.mjs | 2 +- +3 files changed, 211 insertions(+), 1 deletion(-) +``` + +`docs/reviews/CODE-REVIEW-553-r2.md` — публикация предыдущего вердикта, не +предмет разбора. Реальная правка — 15 строк в двух файлах, локальная и не +задевающая новую подсистему: продолжаю разбор по дельте. + +## Закрытие раунда r2 + +Вердикт r2: жёлтый · High 0 · Medium 1 (в скоупе). Материал r2: `55db3d49866adcc35a231fde5a91692806980c97`. + +| Находка r2 | Чем закрыта | Где это видно | +|---|---|---| +| Regression-тест `#553` (`assert.doesNotMatch(process, /ревью[^\n]{0,80}заменяет тестирование/i)`) не пересекает перенос строки — дословный откат абзаца §5 к дореформенной редакции («Код-ревью не пропускается\nникогда — именно оно в этом процессе заменяет тестирование.») проходит мимо теста незамеченным | **Закрыта.** Регэкс заменён на `/ревью[\s\S]{0,120}заменяет тестирование/i` (`test/review-doc-guard.test.mjs`, коммит `f601182a`) — `[\s\S]` пересекает `\n`. Дополнительно в `scripts/mutation-gate.mjs` зарегистрирован постоянный мутант `process-canon-says-review-replaces-testing-across-line-break`, который дословно возвращает старую двухстрочную формулировку и требует, чтобы `node --test --test-name-pattern="#553" test/review-doc-guard.test.mjs` покраснел на этом мутанте — это переводит разовый ручной эксперимент r1/r2 в постоянно исполняемую проверку (нейтрализует нейтральный откат навсегда, а не только для этого захода) | Я лично прогнал `node scripts/mutation-gate.mjs --id=process-canon-says-review-replaces-testing-across-line-break`: `ok чистый прогон` → мутант применён → `ok process-canon-says-review-replaces-testing-across-line-break: заявленный тест покраснел на мутанте` → «поймано 1 из 1». Отдельно проверил, что новый регэкс не матчит текущий (некомпрометированный) `PROCESS.md`: `node -e '...test(process)...'` → `false`. Рабочая копия после эксперимента чиста (`git status --porcelain` пусто) | +| Low: цитата в §11.4 («код-ревью не пропускается никогда») больше не дословно совпадает с текстом §5 | Не тронута в этой дельте — было явно на усмотрение автора («можно поправить … или снять как несущественное»), не входит в перечень противоречий issue | `grep -n "не пропускается никогда" PROCESS.md` → строка 1154 не менялась. Остаётся Low, не блокирует, автор вправе не чинить его в этой задаче | + +## Унаследовано из r2 + +Всё, что дельта не задевает, наследуется из CODE-REVIEW-553-r2 (материал +`55db3d49866adcc35a231fde5a91692806980c97`) без повторной проверки: + +- Все 4 названных в issue противоречия устранены текстуально (замена + тестирования, архивный spec-file при выходе из `small`, `Python 3.13` в + STATUS, точные pins в AGENTS) — проверено построчно в r2, дельта r3 эти + строки не трогает (diff r3 ограничен `scripts/mutation-gate.mjs` и одной + строкой `test/review-doc-guard.test.mjs`). +- Риск-матрица §2.6 и её связь с §2.7 — не задета. +- Rule №1, независимость ревьюера, арбитраж владельца, лимит циклов, + авторизация релиза — разделы вне diff, не задеты. +- Продукт (`src/**`, `custom_components/**/*.py`), changelog, + `docs/specs/**`, история `docs/reviews/**` — не изменены. +- Отсутствие конфликт-маркеров после ребейза (проверялось в r2 на `55db3d49`, + в r3 ребейза не было). + +## Скоуп дельты r3 + +Класс B (`test/review-doc-guard.test.mjs`, `scripts/mutation-gate.mjs`) — +тестовая инфраструктура. Продуктовый код не тронут. Изменение состоит из +двух коммитов: + +- `cc664740` — публикация `docs/reviews/CODE-REVIEW-553-r2.md` (артефакт + прошлого раунда, не предмет разбора этого раунда). +- `f601182a` — целевая правка: расширение регэкса + постоянный мутант. + +Трейлеры обоих коммитов: `Issue: #553`, `User-Visible: no` — корректно, +видимое поведение продукта не меняется, changelog не требуется и не тронут. + +## Как проверялось + +1. Прочитан диф `git diff 55db3d49..f601182a` целиком (оба файла) и сверен + с комментарием автора в issue («Исправление по результатам code review + r2», `2026-09-13T12:06:45Z`). +2. Перечитан вердикт r2 (документ `CODE-REVIEW-553-r2.md`, опубликованный тем + же деревом) и найдена находка Medium, которую эта дельта обязана закрыть. +3. Прогнан целевой тест: `node --test test/review-doc-guard.test.mjs` — 58/58 + (включая изменённый ассерт `#553`). +4. Самостоятельно (не на слово автору) прогнан мутационный свидетель: + `node scripts/mutation-gate.mjs --check --id=process-canon-says-review-replaces-testing-across-line-break` + → `ok` (патч применим к текущему коду), затем полный прогон без `--check` + → «поймано 1 из 1» — тест на мутанте покраснел, как и требуется. Это прямое + доказательство «тест умеет падать» для конкретно этой регрессии, а не + пересказ авторского «Verified». +5. Прогнан `node --test test/mutation-gate.test.mjs` — 51/51 (реестр мутантов + не рассинхронизирован с кодом, новый id учтён корректно). +6. Проверено `git status --porcelain` пусто до и после экспериментов — + рабочая копия не осталась замусоренной операциями мутационного гейта + (использует временный worktree, не трогает основное дерево). +7. Сверены трейлеры обоих коммитов дельты (`git show -s --format=%B`). +8. Сверено соответствие материала: `git rev-parse HEAD` = `f601182a908b5b30a302f122c89265cbf933474c`, + что совпадает с SHA, который автор явно назвал в своём последнем + комментарии — расхождения «материал не запушен до метки» (#437) нет. +9. Проверено, что Validate зелёный именно на этом SHA: + `gh run view` для запуска `34756229263` → `headSha` = `f601182a908b5b30a302f122c89265cbf933474c`, + `conclusion: success`. Отдельно нашёл push-триггернутый прогон на этом же + коммите (`34756084583`, тоже `success`) — совпадает со ссылкой в + комментарии автора. + +## Проверка AC issue (только те, что дельта задевает) + +| AC (из тела issue) | Статус | Доказательство | +|---|---|---| +| «Формулировка о замене testing ревью удалена/исправлена; ясный checklist проверяет результат пользователя» | **Да, полностью** (в r2 было «частично» из-за нерабочей регрессозащиты) | Регэкс пересекает перенос строк, что подтверждено проваленным прогоном на мутанте (см. «Как проверялось», п.4); false-positive на текущем корректном тексте исключён (`test(process)` → `false`) | + +Остальные AC не задеты этой дельтой — наследуются из r2 без повторной +проверки (см. «Унаследовано из r2»). + +## Находки + +Нет. High: 0, Medium: 0. Medium-находка r2 закрыта доказательно (не +заявлением автора, а независимо воспроизведённым прогоном мутационного +гейта). Low-находка r2 (стале-цитата §11.4) остаётся неисправленной, но она +и в r2 была прямо оставлена на усмотрение автора и не входит в перечень +противоречий issue — не блокирует, не эскалируется. + +## Что проверено и корректно + +- Регэкс-гвард `#553` теперь пересекает перенос строки и не матчит текущий + (некомпрометированный) `PROCESS.md`. +- Постоянный мутационный свидетель зарегистрирован, применим к текущему коду + (`--check` → `ok`) и доказательно ловит целевую регрессию (`поймано 1 из 1`), + проверено мной лично, а не на слово. +- Реестр мутантов (`test/mutation-gate.test.mjs`) не рассинхронизирован — + 51/51. +- Трейлеры обоих коммитов дельты корректны, changelog не требовался и не + тронут, продукт (`src/**`, `custom_components/**/*.py`) не изменён. +- Материал ревью соответствует последнему коммиту, названному автором в + issue; Validate зелёный ровно на этом SHA. +- Рабочая копия чиста после всех экспериментов. + +## Чего не проверял + +- `npx tsc --noEmit`, `npm test` (полный), `npm run build` со сверкой + бандла — не перегонял отдельно: покрыты зелёным Validate на точном SHA + `f601182a` (run `34756229263`, `headSha` совпадает, `success`); дельта не + содержит TS и не трогает `src/**`. +- `node scripts/check-docs.mjs` — не применим, diff не трогает `src/**`. +- `npm run invariants -- --config …` — не применим, diff не трогает + геометрию/`layout`/`marker.space`/`open_spans`. +- `python -m pytest tests_backend -q` — не применим, diff не трогает + `custom_components/**/*.py`. +- Браузерные смоки (`demo/smoke_*.mjs`) — не применимы, diff не трогает + исполняемую поверхность карточки; `scripts/smoke-select.mjs` не запускал — + нет продуктового кода в дельте. +- `npm run golden:verify` — не применим, diff не меняет рендер/геометрию/ + стили. +- Полный ночной прогон `mutation-gate.yml` (все мутанты реестра) — не + запускал целиком (дорогой, предрелизный/ночной гейт по PROCESS.md); прогнал + точечно только новый мутант, который и является предметом этой дельты, плюс + дешёвую проверку реестра (`test/mutation-gate.test.mjs`). + +## Вывод + +Дельта r3 доказательно закрывает Medium-находку r2: регрессозащита теперь +переживает перенос строки и подтверждена постоянно исполняемым мутационным +свидетелем, а не разовым экспериментом ревьюера. Новых находок нет. High: 0, +Medium: 0 (в задаче). Вердикт — зелёный. + +--- + +--- + + + +## Материал раунда + +- Ветка: `issue/553-process-doc-canonicalization`, коммит `f601182a908b` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. +- Дерево материала: `c9ea196bdd7b6be335ade3ac9e8c3626245cc9c2` + ``` + git log --all --format='%H %T' | grep c9ea196bdd7b + ``` +- Тело issue: `df64e92bada59856e24d29c886d58c24ba0907508dc476bd206b0e3b1466034d` +- Вердикт конвейера: `green` · High 0