13 KiB
CODE-REVIEW #704 · заход r1
Материал: dd61036b5af84e5dd190803d1c3dce74fa51b5a0 (git log --oneline origin/dev..HEAD — один коммит; git diff origin/dev...HEAD — 5 файлов, +231/-5).
Трек: show. Блокирующих циклов использовано: 0 из 2.
Скоуп
Issue #704: release.yml ставил независимое ревью stable-линии в очередь
токеном GITHUB_TOKEN, прогон стартовал от github-actions[bot], и
claude-code-action отказывал боту без allowed_bots. Родительский workflow
при этом не отличал «dispatch принят» от «ревью реально стартовало».
ТЗ — три AC:
- AC1 —
allowed_botsразрешает ровно ожидаемого бота, не'*'. - AC2 — родительский workflow находит прогон и пишет в сводку ссылку и статус («запущено» / «не стартовало за N минут»); выпуск не блокируется.
- AC3 — unit-тест конфигурации, который ломается при удалении строки.
Изменённые файлы: .github/workflows/release-review.yml,
.github/workflows/release.yml, PROCESS.md, test/release-review.test.mjs,
test/release-workflow.test.mjs. Продуктовый код (src/**) не тронут —
User-Visible: no в трейлере коммита корректен, правка обоих CHANGELOG не
требовалась и не делалась.
Как проверялось
Дешёвые гейты этого SHA уже подтверждены зелёным Validate
(https://github.com/Matysh/houseplan-card/actions/runs/36771523717) —
npx tsc --noEmit, npm test, npm run build повторно не гонялись.
Прогнано в этом раунде:
- Реальное исполнение новых тестов.
node --test test/release-review.test.mjs test/release-workflow.test.mjs— 20/20 зелёных (0 пропущено:hasTools()подтвердил наличиеbash+jq, значит три новых AC2-теста реально исполнили bash-скрипт шага, а не пропустили себя). - Мутационная проверка «тест умеет падать» (вручную, с восстановлением файлов из копии и сверкой
git status/git diff --stat= пусто после):- удалена строка
allowed_bots: "github-actions[bot]"изrelease-review.yml→test/release-review.test.mjsпокраснел ровно на ожидаемой проверке («allowed_bots на месте…»), остальные 8 тестов файла прошли. AC1/AC3 доказаны исполняемым тестом, не только чтением. - в
release.ymlstarted=trueрасширено наqueued(симулирован дефект: шаг посчитал бы очередь «стартом») → 2 из 3 новых AC2-тестов вtest/release-workflow.test.mjsпокраснели («прогон найден и стартовал» и «прогон в очереди — предупреждение»). AC2 доказан исполняемым тестом, не только чтением.
- удалена строка
- Проверка ключевого технического утверждения AC1 (не декларация автора, а сверка с источником). Автор утверждает:
isAllowedBotвclaude-code-actionна пиннутом SHA9cdae7f0d995e3ba7c33f226087fdf82a59cd520сравнивает регистронезависимо и без суффикса[bot]. Получен исходникsrc/github/validation/actor.tsиaction.ymlс этого SHA напрямую из GitHub (gh api repos/anthropics/claude-code-action/contents/...?ref=9cdae7f0...):isAllowedBot(actor, allowedBots):trimmed === '*'→ разрешить всех; иначе списокallowedBots.split(',').map(s => s.trim().toLowerCase().replace(/\[bot\]$/, '')), сравнение сactor.toLowerCase().replace(/\[bot\]$/, ''). Подтверждено дословно.checkHumanActor:allowed_botsконсультируется только когдаactorType !== 'User'(человек список не проходит вообще, как и заявлено в ТЗ/issue-комментарии).action.yml: входallowed_botsсуществует, тип string, default"". Вывод: значение"github-actions[bot]"в диффе корректно совпадает с актёромgithub-actions[bot](оба нормализуются кgithub-actions), любой другой бот по-прежнему отклоняется, человек список не консультирует. AC1 верен по факту, не только по описанию автора.
node scripts/smoke-select.mjs --base origin/dev --head HEAD→ «Исполняемого frontend-диффа нет… Browser-smoke этим диффом не выбираются — выбирать нечего». Подтверждено:src/**/*.tsне тронут.- Прочитаны неизменённые куски контекста:
PROCESS.md§11.5 (описание пайплайна ревью линии, дифф синхронен с кодом), §10.4 (список из шести файлов, требующих немедленного зеркала вmain;release.yml/release-review.ymlв этот список не входят — их собственные комментарии в файле объясняют, почему зеркало не нужно:release-review.ymlдергаетсяworkflow_dispatch --ref dev,release.ymlна событииreleaseчитается с коммита тега, а тег для стабильного всегда ставится с вершиныmain, куда дойдёт обычным промоушеном dev→main перед разрезкой тега — не специальный ручной шаг).
Что проверено и корректно
- AC1.
allowed_bots: "github-actions[bot]"— не'*', сравнение подтверждено по исходнику экшена (см. выше). Комментарий вrelease-review.yml(7 строк) объясняет контекст и ссылается на #704 и наблюдавшуюся ошибку v1.78.0. - AC2. Логика
independent-reviewвrelease.ymlпереписана: dispatch → опросgh run list(окно 180 с, шаг 15 с, что укладывается вtimeout-minutes: 5job — проверено тестом#704 AC2: ожидание прогона укладывается в бюджет job) → четыре различимых исхода, каждый со своей строкой в$GITHUB_STEP_SUMMARYи, где уместно,::warning::: dispatch отклонён (exit 1, как раньше) / прогон не появился за N мин (exit 0) / прогон завис в очереди весь таймаут (exit 0, ссылка в предупреждении) / прогон стартовал (exit 0, ссылка и статус, доп. warning приconclusion: failure). Фильтр поdisplayTitle == "Release review $TAG"иcreatedAt >= since(с запасом в 60 с до dispatch) корректно отсекает старый прогон того же тега — проверено тестом (olderсcreatedAt: iso(-3600)не попадает в сводку) и логически совпадает сrun-name: "Release review ${{ inputs.tag }}"вrelease-review.yml. - AC3. Два новых теста в
test/release-review.test.mjs: точное значение и отсутствие'*'для шагаReview, плюс общий инвариант «ни один workflow не пускаетallowed_bots: '*'» по всем файлам.github/workflows/*.yml. Оба упали при целевой мутации (см. выше). - Документация.
PROCESS.md§11.5 получил абзац, синхронный с кодом (токен dispatch, allowlist, диагностика в сводке, окно в три минуты, ссылка на #704). - Обратная совместимость с #638. Существующий тест
#638 AC2: ревью линии ставится в очередь параллельно гейтам и ни один job выпуска его не ждётпо-прежнему зелёный — новая логика не добавилаneedsнаindependent-reviewи не изменила это свойство. - Трейлеры.
Issue: #704,User-Visible: no— оба корректны, продуктовый код и видимое поведение карточки не затронуты.
Находки
Нет. High — 0, Medium — 0, Low — 0.
Отдельно проверена и отклонена как находка гипотеза «правка release.yml не подействует на следующий stable-релиз без ручного зеркала в main»: §10.4 ограничивает обязательное немедленное зеркалирование шестью конкретными файлами для событий без привязанного ref (issues, schedule, workflow_run); release.yml/release-review.yml в этот список не входят, и release-событие по документированному (и ранее воспроизведённому на v1.78.0 — сам факт, что independent-review вообще выполнился и дошёл до dispatch, подтверждает рабочий путь) поведению читается с коммита тега, который для стабильного релиза всегда ставится с вершины main — то есть обычный промоушен dev → main перед разрезкой тега донесёт этот коммит без отдельного действия.
Чего не проверял
- Живой прогон
claude-code-actionот настоящегоgithub-actions[bot]на реальном GitHub — недоказуемо локально; автор указывает это сам как риск. Компенсировано сверкой с исходником экшена на пиннутом SHA (п. 3 выше), что закрывает основной риск «а вдруг сравнение работает иначе». - Полный
npm run gate:small/tsc/npm test(весь набор) /npm run build— не перегонялись, дешёвые гейты уже зелёные на этом SHA (Validate run 36771523717); прогнаны точечно только два новых тестовых файла. npm run golden:verify,python -m pytest tests_backend,npm run invariants— неприменимы: диффом не затронуты ни рендер, ниcustom_components/**/*.py, ни геометрия/ссылки на неё.- Поведение при реальном
force=trueповторном дергании на тот же тег во время активногоconcurrency-окнаrelease-review-${{ inputs.tag }}(когда прогон реально застревает вqueuedиз-за конкурентности, а не из-за отказа) — логически покрыто веткой «в очереди весь таймаут» и тестом наstatus: queued, но не воспроизведено на реальном раннере.
Вердикт
Зелёный. AC1–AC3 выполнены и доказаны исполняемыми тестами с подтверждённой способностью падать; ключевое техническое утверждение автора (поведение isAllowedBot) проверено по первоисточнику, а не принято на слово. Находок нет.
Материал раунда
- Ветка:
issue/704-stable-review-bot, коммитdd61036b5af8— ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Дерево материала:
888e656fc22851a25640bde167f450fc8b8934d3git log --all --format='%H %T' | grep 888e656fc228 - Тело issue:
c7051f4ce2ca96216b857b0aeb6871cfb32669ec3def1e3b7dcacee82f8979d9 - Вердикт конвейера:
green· High 0