12 KiB
CODE-REVIEW-700-r2
Issue: #700 · Предполёт не красит ветку задачи чужими причинами: зеркало workflow и внешние ссылки
Этап: code · Заход: r2 · Трек: show · Материал: ed3d63e20db24fe9172c83f7ea2e824c90444dcc
(коммит ed3d63e2 поверх материала r1 89d57e054cdf940d3ead83ec509075164118ee3b,
который сам лежит поверх origin/dev @ c716bb0f63104f5afb9d660bc058e095256d433d;
на момент этого раунда origin/dev ушёл на 8 коммитов вперёд, слияние без
конфликта — по треку show ветка к dev не приводится, материал — ветка как есть).
Скоуп раунда
Единственная цель r2 — закрыть единственную находку r1 (Medium, в скоупе):
gh issue list … || true в шаге «Расхождение зеркала на dev — issue
владельцу» (.github/workflows/validate.yml) глушил сбой чтения списка
открытых issue в пустую строку и проваливался в gh issue create, заводя
дубликат [workflow-sync] даже когда нужное issue уже открыто, но недоступно
для чтения (сеть, рейт-лимит).
Дельта r1→r2 — ровно один коммит ed3d63e2, три файла:
.github/workflows/validate.yml | 9 +++++++--
scripts/mutation-registry.mjs | 11 +++++++++++
test/validate-workflow.test.mjs | 3 +++
Дельта локальна и пропорциональна находке (одна правка на одну строку внутри
уже одобренного шага): AC, которые она задевает, — только тот же самый AC про
«одно issue, не дубликат» из тела #700 и контракта PROCESS.md §10.4. Остальной
диапазон (check-docs.mjs, PROCESS.md, test/classify-changes.test.mjs,
test/docs-freshness.test.mjs) не тронут этим коммитом — соответствующая
часть r1 наследуется без повторной проверки (раздел ниже).
Как проверялось
Дешёвые гейты подтверждены зелёным Validate на этом же SHA ed3d63e2
(workflow_dispatch, run 36484635253, conclusion: success, ссылка дана в
задаче ревью) — npx tsc --noEmit, npm test, npm run build +
bundle-policy --verify повторно не гонял.
Дополнительно к зелёному Validate прогнал сам:
| Гейт | Результат |
|---|---|
node --test test/validate-workflow.test.mjs |
27/27 зелёных, включая изменённый #700: на ветке задачи… |
node --test test/classify-changes.test.mjs |
21/21 зелёных (не тронут этим коммитом, для очистки дельты) |
node --test test/mutation-gate.test.mjs |
69/69 зелёных, структура нового мутанта workflow-sync-issue-duplicated-on-read-failure валидна |
node scripts/smoke-select.mjs --base origin/dev --head HEAD |
«Исполняемого frontend-диффа нет» — src/**/*.ts не тронут, браузерные смоки нечего выбирать |
Мутация вручную из реестра: exit 0 → : в новом if-блоке (patch workflow-sync-issue-duplicated-on-read-failure), тест --test-name-pattern="#700: на ветке задачи" |
падает (1 fail, assert.doesNotMatch на ` |
Живое воспроизведение реального сбоя gh issue list на CI не запускал (это
живой internal API-вызов на push в dev, вне доступа из этой сессии, и это
разрушительное действие, если сорвётся не так, как задумано) — как и в r1,
логика закрыта юнит-тестом плюс ручной мутацией guard-команды выше.
Находки
Нет. Правка r2 точна: устраняет ровно описанный в r1 путь, не расширяет и не сужает ничего другого в шаге.
Закрытие раунда r1
| Находка r1 | Чем закрыта | Где это видно |
|---|---|---|
Medium: gh issue list … || true — сбой чтения списка открытых issue проваливается в gh issue create, заводя дубликат [workflow-sync] вместо предупреждения |
|| true убран; чтение обёрнуто в if ! existing=$(gh issue list …); then echo "::warning::…"; exit 0; fi — при ненулевом коде gh issue list шаг предупреждает и выходит, не доходя ни до gh issue comment, ни до gh issue create |
.github/workflows/validate.yml (коммит ed3d63e2, блок шага «Расхождение зеркала на dev — issue владельцу»); поведение зафиксировано тестом test/validate-workflow.test.mjs:628-633 (два новых assert: на форму if !…then…exit 0…fi и на отсутствие || true) до gh issue create) и мутантом workflow-sync-issue-duplicated-on-read-failure в scripts/mutation-registry.mjs, который я применил вручную — тест краснеет на мутированном коде и зеленеет на исходном (таблица гейтов выше) |
Унаследовано из r1
Принято без повторной проверки в этом раунде — документ и материал:
docs/reviews/CODE-REVIEW-700-r1.md (в дереве 545be665), материал
89d57e054cdf940d3ead83ec509075164118ee3b, дерево материала 945dad882326…:
- Периметр
task_branch=true/falseне сузился:check/adviseдля workflow_sync и--external/безwarnдля внешних ссылок остаются красными для push вdevи для кандидата беты/релиза; предупреждением становится только ветка задачи. validate.ymlне входит в список из шести тонких зеркалируемых файлов — этому диффу зеркалирование вmainне требуется.check-docs.mjs:EXTERNAL_WARNкорректно разводитwarnings/errors, выход поerrors.lengthне тронут.- Трейлеры коммита r1 (
Issue: #700,User-Visible: no) — корректны, диффу класса A/D нет. PROCESS.md§10.4 дополнен точно тем, что реализовано в r1.- Оба мутанта r1 (
task-branch-workflow-sync-red-again,external-link-warn-mode-ignored) — краснеют на мутации, зеленеют на исходнике (проверено в r1 вручную). actionlintне перепроверялся (недоступен локально и в r1, и сейчас); косвенно — YAML реально исполнился на CI (run r136482200722и run r236484635253) без ошибки парсинга.
Что проверено и корректно (r2, сверх наследования)
- Новый
if-блок синтаксически и семантически корректен дляbash -eo pipefail(шелл GitHub Actions по умолчанию): присваивание внутри условияif !не триггеритset -e, а код возврата, который проверяется, — код возвратаgh issue list(json/jq считает самgh, не отдельный процесс в пайпе), так что сетевой сбой или рейт-лимит действительно попадает в веткуif, а не проскакивает мимо неё. - Ветка «не прочитано → предупреждение и выход» физически предшествует и
gh issue comment, иgh issue create— при сбое чтения оба этих вызова теперь не выполняются вообще, то есть дубликат исключён, а не просто переименован в другую ошибку. - Комментарий в коде (
# Список не прочитан — …) объясняет неочевидную причину (почему это не «оставить || true»), а не пересказывает код — по стилю совпадает с уже принятыми в r1 комментариями этого же шага. - Новый мутант в реестре (
workflow-sync-issue-duplicated-on-read-failure) минимален и целится ровно в закрытый путь (exit 0→:, единственная правка, из-за которой шаг снова провалился бы вif [ -n "$existing" ]с пустым$existing). - Изменение не расширяет и не меняет скоуп задачи: файлов класса A/D нет,
видимое поведение карточки не меняется,
docs/USER-GUIDE.ru.mdне требует правок. - Одно число, один источник (§8): числовых значений, видимых пользователю карточки, дифф r2 не вводит.
Чего не проверял
mutation-gate --check(полный прогон, а не структура) и весьnpm run gate:small— дешёвые гейты уже подтверждены зелёным Validate на этом SHA, трекshowне запрашивает мутанты по диффу целиком (#696).- Живое исполнение шага «Расхождение зеркала на dev — issue владельцу» с
реально упавшим
gh issue listна push вdev— не воспроизводил (нужен реальный сбой GitHub API или подменаghвнутри Actions-раннера, недоступно из этой сессии); логика закрыта юнит-тестом плюс ручной мутацией, как в r1. golden:verify,pytest tests_backend, инварианты модели, performance — неприменимо, дифф всего диапазона не трогаетsrc/**, рендер, геометрию или Python (подтверждено ещё в r1, r2 диапазон это не меняет).
Вердикт
Единственная находка r1 закрыта точной правкой с тестом и проверенным мутантом; новых находок нет.
Материал раунда
- Ветка:
issue/700-preflight-warnings, коммитed3d63e20db2— ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Дерево материала:
9a8052d18a3baa6cadd0907021a3a01dfc11d935git log --all --format='%H %T' | grep 9a8052d18a3b - Тело issue:
a0c40d40c1401844c3d04ff0695dd347e76172d990004ea2799cc4df38729fce - Вердикт конвейера:
green· High 0