14 KiB
CODE-REVIEW · issue #751 · заход r1
Материал. 616c6185eda9e0ba82a38dcfa1a3d2f5faf070a5 (HEAD), диапазон
origin/dev...HEAD = 1 коммит. origin/dev = 653d94ef, слияние без
конфликта (dev впереди на 5 коммитов, ребейз делает страж слияния один раз).
Трек: show. Validate на этом SHA зелёный:
https://github.com/Matysh/houseplan-card/actions/runs/36875422137.
Скоуп
ТЗ (тело issue #751, трек show) — два принятых по образцу пункта:
- AC1.
set -o pipefailпервой строкойrunперед каждым| teeбез защиты, в трёх местах:_process-resume.yml,release-review.yml,validate.yml(шагheavy). Образец — #727, #472. - AC2. База REST API из
GITHUB_API_URLвместо зашитогоhttps://api.github.comвci-proof.mjs,release-gate.mjs,night-red.mjs. - AC3. Существующие гейты (pipefail-тесты #727/#472,
default-branch-workflows) остаются зелёными, тонкие файлы не тронуты.
Пункт 2 ТЗ (вход mode вместо tag=nightly) явно выведен из скоупа —
правка тонкого файла, отдельная задача. В диффе _ship-review.yml и
ship-review.yml не тронуты — соответствует.
Как проверялось
Дешёвые гейты уже подтверждены на этом SHA (Validate green, см. выше) —
tsc, npm test, npm run build повторно не гонял. Бюджет раунда ушёл на
чтение диффа и на прицельную мутационную проверку двух защитных AC (в
отчёте автора нет протокола запуска с результатом, только словесное
описание — непустая проверка нужна была моя):
- Прочитан полный
git diff origin/dev...HEAD(10 файлов, список поверхностей совпадает с оценкой владельца в issue). - AC1, мутация. Удалил
set -o pipefailиз.github/workflows/_process-resume.yml(sed), прогналtest/workflow-pipefail.test.mjs— 2 из 3 тестов покраснели (AssertionError: _process-resume.yml «…»: падение скрипта прошло зелёным шагом). Вернул файлgit checkout --(рабочая копия чистая,git statusпроверен). - AC2, мутация. Заменил
githubApiBaseвscripts/ci-proof.mjsна функцию, всегда возвращающую жёсткий литералhttps://api.github.com(python-патч, без sed — спецсимволы в regex-литерале мешали sed). Прогналtest/ci-proof.test.mjs test/night-red.test.mjs test/release-gate.test.mjs— было 42/42 зелёных, стало 37/42, 5 упавших. Вернул файлgit checkout --. - Прогнал
test/workflow-pipefail.test.mjs,test/{ci-proof,night-red,release-gate,mutation-gate,ship-review, default-branch-workflows}.test.mjsна исходном дереве — 179/179 зелёных. - Проверил YAML всех трёх изменённых workflow парсером (
python3 -c "yaml.safe_load(...)") — валиден (actionlintв окружении нет, в репозитории нигде не подключён как гейт — заявление автора «actionlint чистый» не перепроверялось инструментом, перепроверено чтением diff). - Прочитал
test/default-branch-workflows.test.mjs— подтвердил спискомTHIN:process-resume.yml(тонкий, не тронут) ≠_process-resume.yml(тело, тронут, верно);validate.ymlиrelease-review.ymlвTHINотсутствуют — тонких файлов правка не касается, как заявлено. - Прочитал оба использования
workflowRunsUrl/githubCandidateTree/loadGithubProofContextвscripts/release-gate.mjs— вызовы без явногоapiBaseопираются на дефолтный параметрgithubApiBase(), вычисляемый в момент каждого вызова (JS default-параметры, не bind-time) — поведение с переменной окружения раннера корректно. - Проверил, что
archive_download_url(абсолютная ссылка из ответа API) не рушится удалением обёртки-переписчика вnight-red.mjs: до правки обёртка переписывала префикс, только если URL начинался ровно с литералаhttps://api.github.com;archive_download_urlвсегда приходит с тем же хостом, что иapiBaseзапроса, — переписывание было фактическим no-op и на GHES, и на github.com. Поведение не изменилось. Тестtest/night-red.test.mjs(actionsClient …) это же подтверждает прогоном с одним акцентом на host. node scripts/smoke-select.mjs --base $(git merge-base origin/dev HEAD) --head HEAD→ «Исполняемого frontend-диффа нет… Browser-smoke этим диффом не выбираются». Связь — отсутствие связи, не слабая; смоки пропущены обоснованно.- Прочитал commit message на трейлеры:
Issue: #751,User-Visible: no— присутствуют, соответствуют факту (CI-инфраструктура, пользователю не видно). Changelog не тронут — верно приUser-Visible: no.
AC · чем доказан · чем краснеет
| AC | Доказательство в материале | Проверено | Чем краснеет (проверено вручную) |
|---|---|---|---|
| AC1 (pipefail) | test/workflow-pipefail.test.mjs — бланковый обход всех .github/workflows/*.yml, плюс bash-исполнение двух реальных шагов под bash -e с падающим node |
Прогнано, зелёное; дополнительно мутация (п.2 выше) | Подтверждено: снятие set -o pipefail из любого защищённого шага красит тест |
| AC2 (база API) | test/ci-proof.test.mjs, test/night-red.test.mjs, test/release-gate.test.mjs — явные URL-ассерты с GHE-базой и с/без GITHUB_API_URL |
Прогнано, зелёное; дополнительно мутация (п.3 выше) | Подтверждено: возврат жёсткого литерала красит 5 тестов из трёх файлов |
| AC3 (гейт) | test/mutation-gate.test.mjs, test/ship-review.test.mjs, test/default-branch-workflows.test.mjs + Validate green на SHA |
Прогнано локально (134/134) и подтверждено ссылкой на CI | Не защитный AC в узком смысле — регресс гейта виден по красному существующему тесту |
Что проверено и корректно
- Три места из аудита issue (
_process-resume.yml:60,release-review.yml:94,validate.yml:371) получилиset -o pipefailстрого до| teeв том же блокеrun, без побочных изменений семантики остальных строк шага. _mutation-gate.ymlи_ship-review.yml(уже защищённые в #472/#727) не тронуты — дельта не задевает принятые образцы.githubApiBase(env)— чистая функция, дефолтprocess.env, убирает хвостовой/;githubCandidateTree,loadGithubProofContext,workflowRunsUrlберутapiBaseпараметром с тем же дефолтом.night-red.mjsпередаёт базу явно и убирает больше ненужную fetch-обёртку, переписывавшую префикс, — поведение на github.com не меняется (дефолт тот же литерал).- Поверхности диффа совпадают с поверхностями, перечисленными владельцем в
оценке issue (
.github/workflows/_process-resume.yml,release-review.yml,validate.yml,scripts/ci-proof.mjs,scripts/night-red.mjs,scripts/release-gate.mjs, новый тест) — без превышения скоупа; пункт 2 ТЗ (входmode) в диффе отсутствует, как и было решено. - Тонкие файлы (
process-resume.yml,ship-review.ymlи др. из спискаTHIN) не затронуты — промоушена вmainэта задача не требует. - Трейлеры
Issue: #751иUser-Visible: noна месте; изменение не несёт видимого пользователю поведения — changelog не нужен и не правился. - Один коммит, сообщение описывает «что» и «почему» (три прежних дефекта, риски регрессии побочных шагов), ссылается на образцы #727/#472.
Чего не проверял
npx tsc --noEmit,npm test(полный),npm run buildсо сверкой бандла — зачтены по зелёному Validate на этом SHA (#343), не перегонял.actionlint— бинарника в окружении нет и в репозитории CI на него не опирается; проверил только синтаксическую валидность YAML парсером, этого достаточно для масштаба правки (три шага, без новых ключей workflow верхнего уровня).- Браузерные смоки,
golden:verify,pytest tests_backend, инварианты модели, performance-профили — не прогонял:smoke-select.mjsне находит frontend-диффа,ci:goldenне проставлена, Python-файлы не тронуты, геометрия/ссылки на неё не тронуты, AC не называет performance-профиль. - Реальный прогон затронутых workflow на GitHub Actions (например,
искусственный fail
classify-changes.mjs --heavyв настоящем прогонеvalidate.yml) — заменён bash-эмуляцией того же шага во временном каталоге (как это делает сам тест) и локальной мутацией тестового файла; это тот же метод, которым пользуется тест, не независимый канал доказательства против ошибки в самом тесте. Риск остаточный и низкий: тест читает реальныеrun-блоки файлов черезfileURLToPath, а не копию.
Находки
Нет. High: 0, Medium (в скоупе): 0, Medium вне скоупа: 0.
Вердикт
Зелёный. AC1–AC3 доказаны тестами, которые я проверил на способность падать (ручная мутация для обоих защитных AC, не только слова автора). Скоуп не расширен и не сужен относительно ТЗ, тонкие файлы не задеты, трейлеры корректны, User-Visible: no подтверждено отсутствием изменений в поведении.
Маршрут (§5 track:show)
| Критерий | Прошёл? |
|---|---|
| complexity | Да — механическая правка по принятому образцу, риск низкий (владелец: сложность 2/10) |
| surfaces | Да — одна связная поверхность: workflow-шаги + их общий модуль построения API-URL, обе части явно описаны в одном ТЗ |
| migration | Да — конфигов и compatibility-полей нет |
| ux-contract | Да — поведения, видимого пользователю карточки, нет (CI-инфраструктура) |
| perf-touch | Да — на производительность и touch-контракт не влияет |
| undocumented | Да — поведение прежде зафиксировано в issue/комментариях шагов #727/#472 (pipefail) и в самом ТЗ (API base); новое не постулируется |
route: fix — задача проходит критерии §5, находок для исправления нет.
Материал раунда
- Ветка:
issue/751-workflow-hygiene, коммит616c6185eda9— ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Дерево материала:
f4a68f5568d1538e607c5176c5456421ca1cabddgit log --all --format='%H %T' | grep f4a68f5568d1 - Тело issue:
eec940f36a11307587569d377e927bfe04888d7ed5abf8b197244f7c7d40fcd6 - Вердикт конвейера:
green· High 0 · маршрутfix