mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-02 12:49:56 +00:00
172 lines
14 KiB
Markdown
172 lines
14 KiB
Markdown
# CODE-REVIEW-587-r1
|
||
|
||
**Вердикт: зелёный · заход r1 · блокирующих циклов 0/4 · High: 0 · Medium: 0**
|
||
|
||
Материал: `978035c49193a7d367d3dba6a22bebef149e1eef` (совпадает с текущим `HEAD`,
|
||
рабочая копия детачнута на нём). Трек: инфраструктурный (метки `bug`, `P2`,
|
||
`infra`, `S7-code-review`; без продуктового `S*`).
|
||
|
||
## Скоуп
|
||
|
||
Один коммит, диапазон `origin/dev..HEAD` = сам коммит `978035c4`. Класс B
|
||
целиком: `.github/workflows/performance.yml`, `scripts/mutation-registry.mjs`,
|
||
`demo/performance/README.md`, плюс новые `scripts/performance-baseline.mjs` и
|
||
`test/performance-baseline.test.mjs`. Продуктовый код (`src/**`,
|
||
`custom_components/**`) не тронут — подтверждено `git diff origin/dev...HEAD
|
||
--stat`.
|
||
|
||
Проблема из issue: гейт «Полных бенчмарков» для кандидата стабильного релиза
|
||
сравнивал линейку саму с собой, потому что `performance.yml` запускается
|
||
только на push в `main`, а базой относительного сравнения брался «предыдущий
|
||
push в main» — то есть первый коммит той же релизной линейки. Наблюдалось
|
||
вживую на v1.76.0: честный красный прогон `35097102695` на `c3d64789` и
|
||
зелёный `35109734519` на `9683a590` независимо от правки бюджетов.
|
||
|
||
Решение: выбор базы вынесен из shell в `scripts/performance-baseline.mjs`;
|
||
стабильный кандидат (head несёт трейлер `Release: vX.Y.Z` без пре-релизного
|
||
суффикса) сравнивается с предыдущим стабильным тегом, остальные случаи
|
||
(бета, обычный push, ручной `comparison_ref`) — без изменений.
|
||
|
||
## Как проверялось
|
||
|
||
Дешёвые гейты для этого SHA уже подтверждены зелёным прогоном Validate
|
||
(системная метка ревью ссылается на `35135781823`; сам исполнитель в хендоффе
|
||
называет соседний прогон `35135276439` — оба независимо проверены мной,
|
||
`headSha` обоих совпадает с материалом ревью, `conclusion: success`):
|
||
`npx tsc --noEmit`, `npm test`, `npm run build` не перегонялись повторно.
|
||
|
||
Что прогнал сам, потому что это точечные, дешёвые и по существу задачи проверки:
|
||
|
||
| Гейт | Команда | Результат |
|
||
|---|---|---|
|
||
| Целевой тест AC2 | `node --test --test-name-pattern="AC2" test/performance-baseline.test.mjs` | зелёный, 1/1 |
|
||
| Мутационный гейт по задаче | `node scripts/mutation-gate.mjs --id=stable-candidate-compares-against-itself` | «заявленный тест покраснел на мутанте» — оба шага (чистый прогон, прогон с мутацией) зелёные в ожидаемом смысле |
|
||
| Реестр мутантов (целостность якорей) | `node scripts/mutation-gate.mjs --check` | прошёл, новый якорь `stable-candidate-compares-against-itself` в списке |
|
||
| Выбор смоков по дифу | `node scripts/smoke-select.mjs --base origin/dev --head HEAD` | «Исполняемого frontend-диффа нет… браузерные смоки этим диффом не выбираются» — `src/**` не тронут, смоки не нужны |
|
||
|
||
Не прогонял и почему:
|
||
- `npm test` целиком, `npx tsc --noEmit`, `npm run build` со сверкой бандла —
|
||
уже зелёные на этом SHA (см. выше), диф не в `src/**`/`custom_components/**`,
|
||
перегонять нет смысла;
|
||
- `node scripts/check-docs.mjs` — диф не трогает `src/**`, отпечаток
|
||
скриншотов документации им не задет; исполнитель называет тот же известный
|
||
устаревший отпечаток (#586), не относящийся к этой задаче;
|
||
- инварианты модели (`npm run invariants`) — диф не касается геометрии, стен,
|
||
`layout`, `marker.space`, `open_spans`;
|
||
- `npm run golden:verify` — диф не меняет рендер/геометрию/стили;
|
||
- `python -m pytest tests_backend -q` — `custom_components/**/*.py` не тронут;
|
||
- performance-профили (реальный прогон бенчмарков) — задача меняет только то,
|
||
*с чем* сравнивается прогон, а не измеряемый код; AC не требуют реального
|
||
запуска `performance.yml`, только доказательства выбора базы, что и
|
||
покрывают юнит-тесты с инжектированным `git`.
|
||
|
||
Дополнительно прочитал код инвариантов, на которые опирается AC4 (см. ниже), и
|
||
сверил регекспы/веточную логику `scripts/performance-baseline.mjs` построчно
|
||
против старой shell-реализации, которую он заменяет.
|
||
|
||
## Разбор по AC (issue #587)
|
||
|
||
**AC1** — «Push в `main` коммита с трейлером `Release: vX.Y.Z` (стабильный)
|
||
берёт базой предыдущий стабильный тег; это видно в сводке прогона.»
|
||
Доказано тестом `AC1: кандидат стабильного релиза судится о предыдущий
|
||
стабильный тег` (`test/performance-baseline.test.mjs:43`) — прогнан лично,
|
||
зелёный. Видимость в сводке: `resolveComparisonBase` возвращает `source`,
|
||
запись в `$GITHUB_STEP_SUMMARY` не убрана (`scripts/performance-baseline.mjs:206-208`),
|
||
проверено чтением — идентична строке из прежней shell-версии.
|
||
Чем краснеет: тот же мутант, что и AC2 (see below) убирает ветку
|
||
`previous-stable` целиком — тест AC1 тоже упал бы на этом мутанте (не
|
||
зарегистрирован отдельно, но код-путь общий: см. «Защитный AC» ниже).
|
||
|
||
**AC2** — «Два коммита подряд одной линейки не могут дать зелёный гейт "сам с
|
||
собой" — второй сравнивается с тем же стабильным тегом, что и первый.»
|
||
Доказано тестом `AC2` — прогнан лично, зелёный. Защитный AC доказан таблицей:
|
||
|
||
| AC | чем доказан | чем краснеет |
|
||
|---|---|---|
|
||
| AC2 | `node --test --test-name-pattern="AC2" test/performance-baseline.test.mjs` | мутант `stable-candidate-compares-against-itself` (`scripts/mutation-registry.mjs`) убирает условие входа в ветку «предыдущий стабильный тег»; прогнал лично `node scripts/mutation-gate.mjs --id=stable-candidate-compares-against-itself` → «заявленный тест покраснел на мутанте» |
|
||
|
||
Для чистого юнита (не дорогой гейт — смок/бэкенд/golden) прогона со снятой
|
||
защитой достаточно по §2.7; сделано.
|
||
|
||
**AC3** — «Бета-кандидат и обычный push сохраняют текущую базу.» Доказано
|
||
тестом `AC3` (тот же файл) — три под-случая (бета с трейлером, push без
|
||
трейлера, `workflow_dispatch` без `comparison_ref`), прогнан лично, зелёный.
|
||
|
||
**AC4** — «Заодно проверить, не опирается ли на "родителя" ещё какой-нибудь
|
||
релизный гейт.» Разобрано **чтением, не исполнением**:
|
||
- `validate.yml` использует `github.event.before` только как `FALLBACK` для
|
||
диапазона классифицируемых файлов (`base`/`range_base`, строки 240–295,
|
||
606, 700); действующая база диапазона — «самый новый предок с успешно
|
||
завершённым Validate» (#387/#388), не сырой родитель — комментарий на
|
||
строке 249 прямо это фиксирует как урок предыдущего инцидента (#86 r5).
|
||
Циклическая проблема из #587 к этой логике неприменима: она не измеряет
|
||
релизную линейку саму собой, а определяет объём проверки файлов.
|
||
- `scripts/release-gate.mjs`, `release-contract.mjs`, `release-membership.mjs`,
|
||
`release-bookkeeping.mjs`, `e2e-gate.mjs` — grep на `parent|HEAD^|event.before`
|
||
ничего не находит; `docs/DEVELOPMENT.md:485-504` подтверждает, что
|
||
`release.yml` резолвит кандидата по точному тегу/SHA и требует полное
|
||
доказательство Validate для этого SHA, родителя не касаясь.
|
||
Вывод соответствует утверждению исполнителя; независимая проверка грепом и
|
||
чтением документации его подтверждает.
|
||
|
||
## Что проверено и корректно
|
||
|
||
- Регекспы `releaseTrailerTag`/`isStableTag` соответствуют существующей
|
||
конвенции трейлера `Release:` в `scripts/classify-changes.mjs` и
|
||
`scripts/process-gate.mjs` — это не новый придуманный контракт, а уже
|
||
используемый в кодовой базе (`docs/DEVELOPMENT.md:489`: стабильный релиз
|
||
обязан нести `Release: <tag>` на кандидате).
|
||
- `previousStableTag` корректно исключает и тег кандидата (по номеру версии,
|
||
independent от текущего SHA — для случая «ремонт уже выпущенного релиза»),
|
||
и тег, стоящий на самой голове; оба случая покрыты тестом
|
||
«свой тег и тег на голове предыдущим не считаются».
|
||
- Порядок отказов (недоступная база → родитель → последний достижимый
|
||
релизный тег → ошибка) сохранён из старой shell-реализации построчно;
|
||
тесты «непригодная база уводит...», «без предыдущего тега...», «база
|
||
старше HP-PERF-01...» подтверждают эквивалентность поведения не-стабильных
|
||
путей.
|
||
- Тест `workflow берёт базу из скрипта...` (`test/performance-baseline.test.mjs:161`)
|
||
проверяет сам YAML-файл: вызов `scripts/performance-baseline.mjs` на
|
||
месте, `HEAD_MESSAGE` прокинут, старая shell-развилка
|
||
(`source="candidate parent"`) удалена целиком — защищает именно от риска
|
||
«два места принятия одного решения расходятся», названного исполнителем.
|
||
- Коммит несёт корректные трейлеры `Issue: #587`, `User-Visible: no` —
|
||
продуктовое поведение не меняется, changelog не требуется.
|
||
- `demo/performance/README.md` обновлён в том же коммите — документация
|
||
подсистемы синхронна с кодом.
|
||
- Одно число — один источник: изменение не вводит новых пользовательских
|
||
величин, дублирования нет (CI-внутренний артефакт, не UI).
|
||
|
||
## Чего не проверял
|
||
|
||
- Реальный прогон `performance.yml` на push в `main` с трейлером `Release:` —
|
||
недоступно из код-ревью (нет push-события), поведение доказано юнит-тестами
|
||
с инжектированным `git`, а не сквозным прогоном workflow. Риск невысокий:
|
||
единственная переменная, которую тесты не видят, — фактический формат
|
||
`github.event.head_commit.message`, но он прокидывается без обработки как
|
||
строка, и `releaseTrailerTag` уже проверен на многострочных сообщениях с
|
||
трейлерами после текста коммита (тест «трейлер релиза читается...»).
|
||
- `npm run mutation-gate` полный прогон всех ~760 мутантов (гонял только
|
||
`--check` для целостности реестра и точечный `--id` для новой записи) —
|
||
полный прогон не относится к дельте этой задачи и дорог.
|
||
|
||
## Материал раунда
|
||
|
||
- SHA: `978035c49193a7d367d3dba6a22bebef149e1eef`
|
||
- Дерево: `git rev-parse HEAD^{tree}` на момент ревью соответствует рабочей
|
||
копии (детач на материале, без локальных изменений — `git status` чист).
|
||
|
||
---
|
||
|
||
<!-- material-anchors: сгенерировано конвейером (#414) -->
|
||
|
||
## Материал раунда
|
||
|
||
- Ветка: `issue/587-stable-perf-baseline`, коммит `978035c49193` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
|
||
- Дерево материала: `8f80b742f032f854e5b54f5184adb4c8daa52cc1`
|
||
```
|
||
git log --all --format='%H %T' | grep 8f80b742f032
|
||
```
|
||
- Тело issue: `ff876b4abd609814b1700c764a650cba2a3ccc262d9ae744e02c16f0d1cbd186`
|
||
- Вердикт конвейера: `green` · High 0
|