From df2455c530b252f7e714ad7a7a6ed2272ba3303a Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Sun, 27 Sep 2026 07:04:23 +0000 Subject: [PATCH] docs: review document for #670 Issue: #670 User-Visible: no --- docs/reviews/CODE-REVIEW-670-r1.md | 151 +++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 docs/reviews/CODE-REVIEW-670-r1.md diff --git a/docs/reviews/CODE-REVIEW-670-r1.md b/docs/reviews/CODE-REVIEW-670-r1.md new file mode 100644 index 00000000..b1cc01bb --- /dev/null +++ b/docs/reviews/CODE-REVIEW-670-r1.md @@ -0,0 +1,151 @@ +# CODE-REVIEW-670-r1 + +Материал: `9bc23f987188febc9b3e4e2346eff09fe79f4612` (issue/670-release-review-index, `git diff origin/dev...HEAD`) +Заход: r1 · блокирующих циклов 0/4 + +## Скоуп + +Issue #670: индексатор `docs/reviews/` (`scripts/reviews-index.mjs`) не знал имени +`RELEASE-REVIEW-vX.Y.Z.md` (документ независимого ревью линии, #638) и молча +клал его в «вне схемы» — после первого прогона на v1.78.0 следующий обычный +push в `dev` красил бы `npm test` (тест живого каталога требует +`skipped.length === 0`). Задача — инфраструктурная (класс B: `test/**`, +`scripts/**`, `.github/workflows/**`; ни одного файла класса A), заведена и +внесена владельцем напрямую, без спеки — соответствует «Infrastructure-only +work» из `AGENTS.md`. Метка на входе — ровно `S7-code-review`, спека не +требовалась. + +Обслуживаемая работа: не пользовательская (документ невидим для персон +`docs/SCOPE.md`), а поддержание самого процесса ревью (канон — `PROCESS.md` +§11.5/§2.10), на который опираются J1–J7 опосредованно через качество кода, +проходящего конвейер. `User-Visible: no` в трейлере коммита корректен. + +## Диапазон изменений (`git diff origin/dev...HEAD`) + +Один коммит `9bc23f98`, трейлеры `Issue: #670` / `User-Visible: no` — оба на +месте. + +- `scripts/reviews-index.mjs` — новый `RELEASE_DOC_NAME`, распознавание + `stage: 'release'` в `parseDocName`, `releaseCounts()` для строки + `Итог: High N · Medium N · Low N`, отдельная секция `releaseDocs` в + `renderIndex` (не участвует в группировке по issue), `--strict` в CLI и + экспорт `assertAllDocumentsIndexed`. +- `.github/workflows/release-review.yml` — публикация зовёт индексатор с + `--strict` вместо голого вызова. +- `scripts/mutation-registry.mjs` — 4 новых мутанта, привязанных к этим + изменениям. +- `test/reviews-index.test.mjs`, `test/release-review.test.mjs` — покрытие + имени, счётчиков, синтетического CLI-теста `--strict` и обновлённая + проверка workflow. + +## Как проверялось + +Дешёвые гейты подтверждены на этом SHA зелёным Validate +(https://github.com/Matysh/houseplan-card/actions/runs/36301186628, +`headSha` сверен командой `gh run view … --json headSha` = материалу) — +`typecheck`, `npm test`, `npm run build` + `bundle-policy --verify` не +перегонялись повторно. + +Прогнано мной в этом раунде: + +| Гейт | Команда | Результат | +|---|---|---| +| Точечные unit-тесты изменённых файлов | `node --test test/reviews-index.test.mjs test/release-review.test.mjs` | 20/20 ok | +| Мутационные свидетели новых защит (4 шт.) | `node scripts/mutation-gate.mjs --id=` для каждого из четырёх новых id | все 4 «поймано 1 из 1» | +| Сверка ссылки на Validate | `gh run view 36301186628 --json headSha,conclusion` | `success`, `headSha` = `9bc23f98…` | + +Не прогонял и почему: `npm run typecheck` / `npm run build` / +`bundle-policy --verify` отдельно — уже зелёные на этом SHA (см. выше), а +диф не трогает ничего, от чего они зависят иначе, чем через `npm test`. +`node scripts/check-docs.mjs` — не требуется, диф не касается `src/**`. +Браузерные смоки, `golden:verify`, `pytest tests_backend`, инварианты +модели, performance — не требуются: диф не трогает `src/**`, +`custom_components/**/*.py`, геометрию или UI; `smoke-select` по этому диффу +не даёт совпадений (нет продуктовых файлов в списке путей). + +## AC · чем доказан · чем краснеет + +Из тела issue #670 («Ожидаемое») и подтверждения автора: + +| AC | Чем доказан | Чем краснеет | +|---|---|---| +| `RELEASE-REVIEW-vX.Y.Z.md` не попадает в `skipped`, получает отдельную строку с этапом «ревью линии» | `parseDocName` тест (`#635 имена документов`) + синтетический каталог (`#635 индекс покрывает…`, теперь с `RELEASE-REVIEW-v1.78.0.md` рядом с обычными документами) | мутант `reviews-index-release-name-unsupported` — прогнан мной, «поймано 1 из 1» | +| Счётчики High/Medium читаются из строки `Итог: High N · Medium N (· Low N)` | `#635 счётчики и находки` (`Итог: High 2 · Medium 4 · Low 1` → `{2,4}`) | мутант `reviews-index-release-counts-ignored` — прогнан мной, «поймано 1 из 1» | +| CLI `--strict` отказывает и НЕ пишет индекс, если в каталоге есть неизвестное имя | `#670 CLI --strict принимает ревью линии и отклоняет неизвестное имя до записи индекса` (сравнивает содержимое файла до/после — не переписан) | мутант `reviews-index-strict-cli-disabled` — прогнан мной, «поймано 1 из 1» | +| Публикация `release-review.yml` сама зовёт индексатор с `--strict` (ловится в момент публикации, не на чужом push) | `#638: только ручной/вызванный запуск…` — `assert.match(publish, /reviews-index\.mjs --dir=docs\/reviews --strict/)` | мутант `release-review-index-without-strict` — прогнан мной, «поймано 1 из 1» | +| Тест живого каталога (`docs/reviews`) остаётся строгим (`skipped.length === 0`) | `#635 живой каталог docs/reviews…` — не изменён, прогнан в составе полного набора | существующий инвариант; для него не заводился новый мутант, но именно он был бы первым красным по сценарию issue до фикса — воспроизведено логически: `RELEASE_DOC_NAME` убрать = вернуть баг issue | + +Третий столбец пуст ни в одной строке — прогнал все четыре новых мутанта +лично, не полагаясь на слова автора. + +## Что проверено и корректно + +- Регекс `RELEASE_DOC_NAME` требует ровно стабильный тег (`v(?:0|[1-9]\d*)\.…`, + без бета-суффикса) — согласовано с `STABLE_TAG_RE` / + `releaseReviewDocPath()` в `scripts/release-review.mjs`: индекс не примет + то, что публикатор никогда не создаст под этим именем. +- `--strict` бросает исключение **до** `renderIndex`/`writeFileSync` — + прочитано в коде (`scripts/reviews-index.mjs:382-384`) и подтверждено + тестом, сравнивающим байты файла до/после отказа. +- В `release-review.yml` шаг «Опубликовать документ» — обычный + `run:` (bash с `errexit` по умолчанию в Actions); ненулевой код + `reviews-index.mjs --strict` останавливает шаг до `git add`/`commit`/`push` — + прочитано по месту вызова в workflow, без выполнения самого workflow + (недоступно вне CI релиза). +- `renderIndex` выносит записи стадии `release` в отдельный блок и исключает + их из `byIssue`, поэтому подсчёт `issue: M` в шапке индекса не меняется — + проверено на синтетическом каталоге (`Документов: 5, issue: 2`). +- `parseVerdict` для документа ревью линии закономерно возвращает `—` + (⚪): в этих документах нет слова «Вердикт», только рекомендательный + `Итог:` (доказано и разъяснено в самом workflow: «Выпуск не блокирует; + решение — за владельцем», `PROCESS.md` §11.5) — это ожидаемое поведение, + не находка. +- Коммит несёт единственные необходимые трейлеры (`Issue: #670`, + `User-Visible: no`); правки продуктового кода/changelog отсутствуют, как и + требуется при `User-Visible: no`. +- Одно число, видимое дважды: не применимо — diff не меняет ничего + пользовательского (§8); единственные числа — High/Medium счётчики самого + документа ревью, и их источник теперь ровно один (`releaseCounts`), что и + было целью AC. + +## Чего не проверял + +- Реальный прогон `release-review.yml` end-to-end (недоступен вне CI релиза; + первый настоящий документ линии появится только на v1.78.0) — доверяю + юнит-тестам workflow-текста и ручному чтению шага публикации. +- `npm run typecheck` / `npm run build` / `bundle-policy --verify` отдельно — + полагаюсь на зелёный Validate этого же SHA (ссылка сверена по `headSha`). +- Смоки, golden, backend pytest, инварианты модели, performance — не + запускал: ни диф, ни AC их не требуют (нет изменений в `src/**`, + `custom_components/**/*.py`, геометрии, UI). +- Дублирование регулярного выражения стабильного тега между + `RELEASE_DOC_NAME` (`scripts/reviews-index.mjs`) и `STABLE_TAG_RE` + (`scripts/release-review.mjs`) — оба протестированы порознь и синхронно + верны сейчас; не находка (в скоуп задачи общий модуль не входил), но + наблюдение на будущее, если формат тега когда-нибудь изменится в одном + месте и не в другом. + +## Находки + +Нет. High: 0, Medium: 0, Low: 0. + +## Вердикт + +Зелёный. Все AC из issue закрыты, каждая защита доказана собственным +мутационным свидетелем, который я прогнал лично (не со слов автора), полный +набор точечных unit-тестов зелёный, дешёвые гейты подтверждены Validate на +материале ревью. + +--- + + + +## Материал раунда + +- Ветка: `issue/670-release-review-index`, коммит `9bc23f987188` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. +- Дерево материала: `0c8ab8e9b1f02e7d81bdeee9c20cc148355b7bd2` + ``` + git log --all --format='%H %T' | grep 0c8ab8e9b1f0 + ``` +- Тело issue: `e0236f9a259cedeffac806fe8969399f8f5251128520323f50e109c591727f2a` +- Вердикт конвейера: `green` · High 0