Files
houseplan-card/docs/reviews/CODE-REVIEW-670-r1.md
T
2026-09-27 07:04:23 +00:00

12 KiB
Raw Blame History

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 на материале ревью.


Материал раунда

  • Ветка: issue/670-release-review-index, коммит 9bc23f987188 — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
  • Дерево материала: 0c8ab8e9b1f02e7d81bdeee9c20cc148355b7bd2
    git log --all --format='%H %T' | grep 0c8ab8e9b1f0
    
  • Тело issue: e0236f9a259cedeffac806fe8969399f8f5251128520323f50e109c591727f2a
  • Вердикт конвейера: green · High 0