mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
docs: review document for #551
Проверка (CI) / Предполёт: документация, провенанс, процесс (push) Failing after 40s
Проверка (CI) / Классификация изменённых файлов (push) Successful in 32s
Проверка (CI) / Мутанты по диффу (1/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Мутанты по диффу (2/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Мутанты по диффу (3/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Мутанты по диффу (6/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Фронтенд: типы, юниты, мутанты, синхрон бандла (push) Skipped
Проверка (CI) / HACS: валидация репозитория (push) Skipped
Проверка (CI) / Hassfest: манифест интеграции (push) Skipped
Проверка (CI) / Мутанты по диффу (4/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Мутанты по диффу (5/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Переиспользование: это дерево уже проверено (push) Failing after 46s
Проверка (CI) / Смоки в браузере (шард 1 из 3) (push) Skipped
Проверка (CI) / Смоки в браузере (шард 2 из 3) (push) Skipped
Проверка (CI) / Смоки в браузере (шард 3 из 3) (push) Skipped
Проверка (CI) / Смоки: все шарды зелёные (push) Skipped
Проверка (CI) / Golden-кадры против принятых эталонов (push) Skipped
Проверка (CI) / Перф-смок: бюджет времени кадра (push) Skipped
Проверка (CI) / Геометрия: TS/Python parity исполнена (push) Skipped
Проверка (CI) / Бэкенд: pytest в Home Assistant (push) Skipped
Проверка (CI) / Доказательство выполненных проверок (push) Failing after 25s
Проверка (CI) / Предполёт: документация, провенанс, процесс (push) Failing after 40s
Проверка (CI) / Классификация изменённых файлов (push) Successful in 32s
Проверка (CI) / Мутанты по диффу (1/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Мутанты по диффу (2/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Мутанты по диффу (3/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Мутанты по диффу (6/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Фронтенд: типы, юниты, мутанты, синхрон бандла (push) Skipped
Проверка (CI) / HACS: валидация репозитория (push) Skipped
Проверка (CI) / Hassfest: манифест интеграции (push) Skipped
Проверка (CI) / Мутанты по диффу (4/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Мутанты по диффу (5/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Переиспользование: это дерево уже проверено (push) Failing after 46s
Проверка (CI) / Смоки в браузере (шард 1 из 3) (push) Skipped
Проверка (CI) / Смоки в браузере (шард 2 из 3) (push) Skipped
Проверка (CI) / Смоки в браузере (шард 3 из 3) (push) Skipped
Проверка (CI) / Смоки: все шарды зелёные (push) Skipped
Проверка (CI) / Golden-кадры против принятых эталонов (push) Skipped
Проверка (CI) / Перф-смок: бюджет времени кадра (push) Skipped
Проверка (CI) / Геометрия: TS/Python parity исполнена (push) Skipped
Проверка (CI) / Бэкенд: pytest в Home Assistant (push) Skipped
Проверка (CI) / Доказательство выполненных проверок (push) Failing after 25s
Issue: #551 User-Visible: no
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
# CODE-REVIEW-551-r4
|
||||
|
||||
## Скоуп
|
||||
|
||||
Issue #551 (инфраструктурная, метка `infra`) — разнесение конвейера ревью на
|
||||
три job с независимыми бюджетами. Раунды r1–r3 уже признали конструкцию
|
||||
выполненной (зелёный, без находок); в задачу этот вердикт до сих пор не
|
||||
применён — оба последних захода (r2, r3) закончились зелёной моделью, но
|
||||
**стадия публикации/интеграции падала** на живых прогонах уже после
|
||||
слияния/повторной активации `process.yml`, и автор возвращал задачу в
|
||||
`S6-in-progress` для фикса именно интеграции, а не по замечанию ревью.
|
||||
|
||||
Материал этого раунда — ровно `62e0eff21999eebfc9aecbfe99edb14d9ccf716f`.
|
||||
Дельта отсчитывается от материала r2/r3 (`23f48829c26deec968af6645301900880899139e`,
|
||||
дельта r2 от r3 — нулевая, см. ниже): один коммит `62e0eff2` поверх
|
||||
`23f48829`, 3 файла, +26/−5 строк (`git diff --shortstat 23f48829..62e0eff2`):
|
||||
|
||||
- `.github/workflows/process.yml` — шаг «Проверить полноту и происхождение
|
||||
результата» в job `integrate`: запись `structured_output` в
|
||||
`$GITHUB_OUTPUT` заменена с `{ echo <<EOF_RESULT; cat verdict.json; echo
|
||||
EOF_RESULT; }` на явный `printf` с гарантированным `\n` перед закрывающим
|
||||
delimiter'ом;
|
||||
- `scripts/mutation-gate.mjs` — новый мутант
|
||||
`review-integration-delimiter-follows-json-without-newline`;
|
||||
- `test/review-doc-guard.test.mjs` — два новых `assert` в существующем тесте
|
||||
`#551: gates, модель и интеграция…`, закрепляющие фикс.
|
||||
|
||||
Класса A нет (тот же трек, что r1–r3), ТЗ/ревью ТЗ не требуются.
|
||||
|
||||
## Что чинит эта дельта (по логам, не со слов автора)
|
||||
|
||||
Живой дефект: run [34754400084](https://github.com/Matysh/houseplan-card/actions/runs/34754400084)
|
||||
упал в `integrate` с `Matching delimiter not found` при чтении
|
||||
`structured_output`. Причина в бывшем коде: `cat "$dir/verdict.json"` пишет
|
||||
JSON как есть (если файл без завершающего LF — а `jq -e`/сериализаторы это не
|
||||
гарантируют), а следующая по счёту команда `echo 'EOF_RESULT'` в блоке `{ ...
|
||||
} >> file` — это отдельный `write()`, который ничего не подставляет между
|
||||
предыдущим выводом и своим: без LF в конце JSON delimiter приклеивается к
|
||||
последней строке значения, и GitHub Actions не находит начало delimiter'а на
|
||||
отдельной строке.
|
||||
|
||||
Фикс (`process.yml:1212-1216` после дельты):
|
||||
```
|
||||
printf 'structured_output<<EOF_RESULT\n' >> "$GITHUB_OUTPUT"
|
||||
cat "$dir/verdict.json" >> "$GITHUB_OUTPUT"
|
||||
printf '\nEOF_RESULT\n' >> "$GITHUB_OUTPUT"
|
||||
```
|
||||
Явный `\n` перед `EOF_RESULT` гарантирует делимитер на отдельной строке
|
||||
независимо от того, кончается ли `verdict.json` переводом строки. Если файл
|
||||
уже кончается LF — на выходе будет один лишний пустой перенос перед
|
||||
delimiter'ом; это не влияет на `jq`-парсинг ниже по конвейеру (`OUT: ...
|
||||
structured_output`, `printf '%s' "$OUT" | jq -r`) — JSON с хвостовым
|
||||
whitespace для `jq` эквивалентен исходному. Прочитано и проверено вручную.
|
||||
|
||||
Это прямое попадание в AC3 issue («timeout/cancel/**failure** каждой стадии
|
||||
оставляет понятное состояние; лимиты review cycles не расходуются на
|
||||
невыполненный review») — двумя живыми прогонами (r2→r3 и r3→r4) подтверждено,
|
||||
что счётчик циклов действительно не тратился на несостоявшуюся интеграцию
|
||||
(«блокирующих циклов израсходовано 0 из 4» в постановке этого захода), т.е.
|
||||
защитное свойство AC3 сработало даже при поломке самой публикации.
|
||||
|
||||
## Проверено
|
||||
|
||||
- `git diff 23f48829..62e0eff2` — три файла, ровно эти три хунка, ничего
|
||||
лишнего; job `guard`, `prepare`, `model_review`, структура контракта,
|
||||
проверки sha256/полей — не тронуты ни строкой.
|
||||
- Прочитано построчно: новый код в `process.yml:1212-1216` синтаксически и
|
||||
семантически корректен (см. разбор выше), остальной шаг («Проверить
|
||||
полноту и происхождение результата») не менялся вне этих трёх строк.
|
||||
- Независимо (не полагаясь на заявление автора) прогнал:
|
||||
- `node --test --test-name-pattern="#551" test/review-doc-guard.test.mjs`
|
||||
→ 1/1 pass;
|
||||
- `node scripts/mutation-gate.mjs --id=review-integration-delimiter-follows-json-without-newline`
|
||||
→ «чистый прогон» + «заявленный тест покраснел на мутанте» → **поймано 1
|
||||
из 1**. Мутант возвращает ровно старый баг (`printf 'EOF_RESULT\n'` без
|
||||
ведущего `\n`), и новый `assert.match(resultOutput, /cat ...>>
|
||||
"\$GITHUB_OUTPUT"[\s\S]*printf '\\nEOF_RESULT\\n' >>.../)` действительно
|
||||
красится на этом мутанте — дисциплина «тест умеет падать» соблюдена для
|
||||
прогнанного мной гейта.
|
||||
- `node scripts/smoke-select.mjs --base 23f48829 --head 62e0eff2` →
|
||||
«Исполняемого frontend-диффа нет… Browser-smoke этим диффом не
|
||||
выбираются» — выбирать нечего, `src/**` не тронут.
|
||||
- ID нового мутанта уникален в реестре (`grep -n
|
||||
'review-integration-delimiter-follows-json-without-newline'
|
||||
scripts/mutation-gate.mjs` — одно определение), guard-команда та же, что и
|
||||
у соседних #551-мутантов, конфликтов нет.
|
||||
- Трейлеры коммита `62e0eff2`: `Issue: #551`, `User-Visible: no` — верно,
|
||||
правка меняет только служебный CI-механизм передачи данных между stages,
|
||||
видимое поведение продукта не меняется; changelog не требуется.
|
||||
|
||||
Не перегонял `npx tsc --noEmit` / `npm test` / `npm run build` + сверку трёх
|
||||
копий бандла — Validate зелёный на этом точном SHA:
|
||||
https://github.com/Matysh/houseplan-card/actions/runs/34754874119 (упомянут
|
||||
автором и подтверждён как ссылка на прогон именно этого коммита). Не
|
||||
перегонял `check-docs.mjs`, `golden:verify`, backend pytest, инварианты
|
||||
модели, performance-профили и полный набор browser-смоков — diff не касается
|
||||
`src/**` (кроме тестового файла `test/review-doc-guard.test.mjs`, не
|
||||
влияющего на отпечаток документации), Python, геометрии/`layout`/
|
||||
`marker.space`/`open_spans`, визуального рендера или производительности;
|
||||
`smoke-select.mjs` подтверждает пустой отбор.
|
||||
|
||||
## Закрытие раунда r3
|
||||
|
||||
r3 не содержал находок («Находок нет», зелёный, High 0 / Medium 0) — этому
|
||||
раунду нечего закрывать по замечаниям. Причина существования r4 —
|
||||
операционный сбой стадии публикации/интеграции ПОСЛЕ зелёного вердикта r3
|
||||
(run [34754400084](https://github.com/Matysh/houseplan-card/actions/runs/34754400084)),
|
||||
диагностированный автором как отдельный дефект границы стадий (delimiter
|
||||
приклеен к JSON). Дельта этого раунда — прямой фикс именно этого сбоя (см.
|
||||
разбор выше); других изменений кода в диапазоне r3→r4 нет.
|
||||
|
||||
## Унаследовано из r3 (без повторной проверки)
|
||||
|
||||
Документ r3 не был закоммичен в `docs/reviews/` (интеграция того захода
|
||||
упала на дефекте, который правит именно материал этого раунда) — источник
|
||||
вывода r3: комментарий ревью в issue #551 от 2026-09-13T11:29:02Z, материал
|
||||
`23f48829c26deec968af6645301900880899139e` (дельта от r2/r3 к r4 — только
|
||||
три файла выше, всё остальное дерево идентично). Наследуется:
|
||||
|
||||
- разнесение конвейера на три job (`prepare`/`model_review`/`integrate`) с
|
||||
независимыми бюджетами 55/45/55 минут и их назначение по коду —
|
||||
подтверждено в r1 (`docs/reviews/CODE-REVIEW-551-r1.md`, материал `31ef70ce`)
|
||||
и повторно не тронуто ни в r2, ни в r3, ни в этой дельте;
|
||||
- контракт передачи между стадиями (`prepared.json`/`manifest.sha256`,
|
||||
полная сверка полей через `jq -e`, `git rev-parse HEAD`/`HEAD^{tree}`
|
||||
против заявленного материала) — из r1, не задет;
|
||||
- поведение при timeout/cancel/failure каждой стадии и правило «ранний отказ
|
||||
не расходует цикл» — из r1, не задет; двумя живыми провалами интеграции
|
||||
(r2→r3, r3→r4) это правило дополнительно эмпирически подтверждено вне
|
||||
ревью;
|
||||
- отказ на неполном/чужом evidence (точный набор имён файлов artifact'а,
|
||||
sha256, отказ от failed/cancelled/skipped результата модели) — из r1, не
|
||||
задет;
|
||||
- фикс r2 «structured verdict сохраняется как объект, а не boolean предиката
|
||||
`jq -e`» (`process.yml`, шаг «Запечатать результат модели», строки до
|
||||
`- name: Передать результат интеграции`) и его мутационный свидетель
|
||||
`review-model-seals-verdict-as-boolean` — заявлен в r2, независимо
|
||||
перепроверен в r3 (`node --test --test-name-pattern="#551"` + прогон
|
||||
мутанта, «поймано 1 из 1»); дельта r3→r4 этот шаг не трогает
|
||||
(`git diff 23f48829..62e0eff2` не включает диапазон `seal`), поэтому
|
||||
принимается без повторного прогона в этом раунде;
|
||||
- три исходных мутационных свидетеля r1 (`review-model-checks-out-moving-dev`,
|
||||
`review-integration-skips-evidence-checksum`,
|
||||
`review-integration-trusts-failed-model`) — из r1, не задеты ни одной
|
||||
дельтой r2/r3/r4.
|
||||
|
||||
## Найдено
|
||||
|
||||
Находок нет — ни High, ни Medium, ни Low.
|
||||
|
||||
## Не проверялось (и почему)
|
||||
|
||||
- Полный набор `tsc`/`test`/`build`+сверка бандла, `check-docs.mjs`,
|
||||
`golden:verify`, backend pytest, инварианты модели, performance-профили,
|
||||
полный набор browser-смоков — не требуются по соразмерности (PROCESS.md
|
||||
§8) и по факту зелёного Validate на этом точном SHA (см. выше) плюс
|
||||
пустому отбору `smoke-select.mjs`.
|
||||
- Реальное поведение исправленного шага в проде за пределами уже
|
||||
показанных run — не переисполнялось повторно мной (GitHub Actions
|
||||
недоступен для интерактивного запуска из этого ревью); проверка —
|
||||
чтением кода плюс воспроизведением локального юнит-теста и мутанта,
|
||||
которые моделируют тот же самый путь (`process.yml`-текст плюс regex по
|
||||
нему), а не реальным запуском workflow.
|
||||
|
||||
## Вердикт
|
||||
|
||||
Зелёный. Дельта r4 — точечный фикс одной строки протокола передачи данных
|
||||
между стадиями (`GITHUB_OUTPUT` delimiter), выявленный вторым живым прогоном
|
||||
после r3. Фикс корректен (разобран построчно), закреплён тестом и
|
||||
мутационным свидетелем, который я прогнал независимо и подтвердил, что он
|
||||
красит именно старое поведение. Всё содержательное из AC issue #551
|
||||
(разнесение бюджетов, контракт, отказ на неполном evidence, поведение при
|
||||
провале стадии) наследуется из r1 без изменений; правка r2 (boolean-подмена)
|
||||
перепроверена в r3 и не задета этой дельтой. Находок нет, скоуп не расширен.
|
||||
|
||||
---
|
||||
|
||||
<!-- material-anchors: сгенерировано конвейером (#414) -->
|
||||
|
||||
## Материал раунда
|
||||
|
||||
- Ветка: `issue/551-review-stage-budgets`, коммит `62e0eff21999` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
|
||||
- Дерево материала: `8ea4718a882bb877b6288a234823406709f5659c`
|
||||
```
|
||||
git log --all --format='%H %T' | grep 8ea4718a882b
|
||||
```
|
||||
- Тело issue: `824f489aab52c7d76ade6634cbdb819c9c36ff9261ae2982484d5199a4bc23d0`
|
||||
- Вердикт конвейера: `green` · High 0
|
||||
Reference in New Issue
Block a user