docs: review document for #670

Issue: #670
User-Visible: no
This commit is contained in:
claude[bot]
2026-09-27 07:04:23 +00:00
parent 9bc23f9871
commit df2455c530
+151
View File
@@ -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>` для каждого из четырёх новых 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 на
материале ревью.
---
<!-- material-anchors: сгенерировано конвейером (#414) -->
## Материал раунда
- Ветка: `issue/670-release-review-index`, коммит `9bc23f987188` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
- Дерево материала: `0c8ab8e9b1f02e7d81bdeee9c20cc148355b7bd2`
```
git log --all --format='%H %T' | grep 0c8ab8e9b1f0
```
- Тело issue: `e0236f9a259cedeffac806fe8969399f8f5251128520323f50e109c591727f2a`
- Вердикт конвейера: `green` · High 0