12 KiB
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.ymlend-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— ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Дерево материала:
0c8ab8e9b1f02e7d81bdeee9c20cc148355b7bd2git log --all --format='%H %T' | grep 0c8ab8e9b1f0 - Тело issue:
e0236f9a259cedeffac806fe8969399f8f5251128520323f50e109c591727f2a - Вердикт конвейера:
green· High 0