18 KiB
CODE-REVIEW-632-r3
Issue: #632 · этап: код-ревью · заход r3 · блокирующих циклов израсходовано 1 из 4 Трек: инфраструктурный (ускоренный вход, AGENTS.md §1 / PROCESS.md §1) — весь дифф класса B, ни одного файла класса A (подтверждено ниже).
Материал: HEAD = 14396ed0b186dc9b883f0b26e460458828dcb58c
(«docs(reviews): индекс после сдвига каталога (#632)»), рабочая копия уже на
нём. git log --oneline origin/dev..HEAD: 5 коммитов; git diff origin/dev...HEAD --stat:
docs/reviews/CODE-REVIEW-632-r1.md | 231 ++++++++++++++
docs/reviews/CODE-REVIEW-632-r2.md | 202 ++++++++++++++
docs/reviews/INDEX.md | 4 +-
scripts/mutation-registry.mjs | 44 +++++++
scripts/task-packet.mjs | 51 ++++++-
test/task-packet.test.mjs | 69 ++++++-
Почему это r3, а не продолжение зелёного r2 — реконструкция по issue и логам
r2 (docs/reviews/CODE-REVIEW-632-r2.md, материал b64bc932) уже вынес
зелёный вердикт: High 0, Medium 0. Зелёный цикла не образует и должен
двигать задачу вперёд (§4). То, что ревью назначено снова, — не сигнал о
находке, а следствие события после вердикта; разобрал по комментариям issue
и логам CI, а не со слов автора:
- Пока шло ревью r2,
devпродвинулся на 2 коммита; автор перебазировал ветку наdev@c8f9b5d3→ кандидат1e866291. - Validate на
1e866291красный (run35949058000,conclusion: failure, провереноgh run view). Разобрал сам, какой именно job/шаг упал:Упал только предполётный job; все мутантные шарды и фронтенд-гейт — зелёные на этом кандидате. Внутри упавшего job — конкретно шаг$ gh run view 35949058000 --json headSha,conclusion,status,jobs headSha 1e86629189ddf61eacae82fac281b7a13915611a conclusion failure Предполёт: документация, провенанс, процесс failure Фронтенд: типы, юниты, мутанты, синхрон бандла success Мутанты по диффу (1..6/6) success (все шесть шардов)workflow_sync:Это проверка «$ gh run view 35949058000 --log-failed | grep -i "process.yml\|различаются" РАСХОЖДЕНИЕ: process.yml в main и dev различаются. mutation-gate.yml: main и dev идентичны process-resume.yml: main и dev идентичны FAIL process.yml и mutation-gate.yml в main и dev (failure).github/workflows/process.ymlвmainсовпадает сdev» — репозиторного уровня инвариант, никак не зависящий от дерева ветки #632 (её диф вообще не трогает.github/workflows/**, см. список файлов выше). Причина расхождения — независимая правка #634 вmain, не отражённая в зеркале; сам автор её так и определил в issue. - Автор зеркалировал
main(main = 7752329d) и переподписал вершину без изменения дерева:14396ed0имеет то же дерево, что и кандидат до переподписания (дерево0d959028, по словам автора) — я это не принимаю на слово, а проверяю ниже блобами по каждому файлу.
Итог: r3 — не ревью новой правки, а подтверждение, что дерево, получившее зелёный вердикт в r2, не изменилось, и что сорвавшийся кандидат упал по причине, не относящейся к #632. Разбираю дельту, а не задачу целиком (PROCESS.md §2.10) — она пуста по коду.
Тождество дерева r2 → r3 (проверено блобами, не заявлением)
docs/reviews/CODE-REVIEW-632-r2.md называет SHA материала b64bc932,
который в этом дереве не резолвится (ожидаемо — ребейз, тот же паттерн, что
уже был у r1→r2). Материал восстановлен не по SHA, а по содержимому:
$ git ls-tree HEAD -- scripts/task-packet.mjs test/task-packet.test.mjs scripts/mutation-registry.mjs
100644 blob f07f56b64e7b92b67b32654481b28e718788de6e scripts/mutation-registry.mjs
100644 blob c7bfebd2904fca3360b11eacedf9343d768e7915 scripts/task-packet.mjs
100644 blob 15b9c04786b6733c8564c3173f700f374cc5b22d test/task-packet.test.mjs
scripts/task-packet.mjs (c7bfebd2…) и test/task-packet.test.mjs
(15b9c047…) — точное совпадение блобов, названных в r2-документе как
материал ревью. Это не эквивалент по содержимому, это тот же самый файл
байт в байт: решающая логика и тесты, за которые r2 выдал зелёный вердикт,
не изменились ни на символ.
scripts/mutation-registry.mjs в r2-документе назван другим блобом
(e48ddb98…, тоже мёртвый), текущий — f07f56b6…. Как и в r1→r2 (там же
объяснялось: между ребейзами dev получает чужие правки того же файла от
других issue), проверил, что содержимое трёх/четырёх мутантов #632 внутри
не пострадало — не по аналогии с прошлым разом, а прогоном на этом SHA:
$ node --test test/task-packet.test.mjs
# tests 14, pass 14, fail 0
$ node scripts/mutation-gate.mjs --check | grep task-packet
ok task-packet-product-flow-overrides-diff
ok task-packet-review-docs-not-material
ok task-packet-s6-s7-alone-not-product-flow
ok task-packet-trivial-is-product-flow
$ node scripts/mutation-gate.mjs --id=task-packet-trivial-is-product-flow
ok чистый прогон: node --test test/task-packet.test.mjs
ok task-packet-trivial-is-product-flow: заявленный тест покраснел на мутанте
поймано 1 из 1
$ git status --porcelain # после гейтов — пусто
Все четыре мутанта задачи (включая trivial-is-product-flow, закрывший
Medium из r1) на месте и красят ровно то, что заявлено — защитное свойство
доказано исполнением на текущем SHA, не унаследовано голословно.
Закрытие раунда r2
r2 не оставил находок (High 0, Medium 0) — таблицы «находка → чем закрыта»
формально нет. Единственное, что произошло между вердиктом r2 и этим
раундом, — событие вне дерева задачи (провал предполётного workflow_sync
на промежуточном кандидате 1e866291 из-за расхождения process.yml между
main/dev, вызванного другой задачей #634). Проверил, что расхождение
устранено и не является скрытой находкой против #632:
$ git fetch origin main dev --quiet # только чтение ссылок, HEAD/рабочая копия не менялись
$ git diff origin/main origin/dev -- .github/workflows/process.yml
(пусто)
process.yml в main и dev теперь идентичны — зеркало восстановлено,
причина красного дispatch снята. git rev-parse HEAD после fetch — та же
14396ed0…, рабочая копия не трогалась (см. правило §2.7/#312 — не уходить
с материала ревью; fetch не меняет ни HEAD, ни индекс, только обновляет
удалённые ссылки для чтения).
Унаследовано из r2 (и транзитивно из r1)
Дельта по коду между r2 и r3 пуста (см. блобы выше), поэтому решающая логика повторно вручную не переразбиралась — но защитные тесты и мутанты перепрогнаны на этом SHA заново (не просто приняты на слово):
- AC1 (продуктовая S6-задача с ТЗ/ревью ТЗ сохраняет право класса A) —
документ
docs/reviews/CODE-REVIEW-632-r1.md, мутантtask-packet-product-flow-overrides-diff— ok на этом SHA (выше). - AC2 (
docs/reviews/**не влияет на классификацию ветки) — тот же документ, мутантtask-packet-review-docs-not-material— ok на этом SHA. - AC3 (настоящая инфраструктурная задача без ТЗ сохраняет запрет) —
тот же документ, мутант
task-packet-s6-s7-alone-not-product-flow— ok на этом SHA. - AC4 (каждый признак самодостаточен;
## ТЗшкане считается разделом ТЗ) — регэксп(?![\p{L}\p{N}_])не менялся (блобtask-packet.mjsидентичен r2); тест на эту границу входит в те же 14 зелёных. - Medium r1 (
trivial-трек не входил в признаки продуктового потока) — закрыт в r1-фиксе, документdocs/reviews/CODE-REVIEW-632-r2.md, мутантtask-packet-trivial-is-product-flow— ok на этом SHA (перепрогнан выше, «поймано 1 из 1», не только унаследован). - Трейлеры и класс файлов — сверены заново на этом SHA (раздел ниже), не унаследованы.
Находки
Нет. High: 0. Medium: 0.
Дерево, за которое r2 выдал зелёный вердикт, не изменилось (байт в байт по
двум решающим файлам); дельта — это только публикация документов ревью и
восстановление зеркала process.yml, вызвавшего посторонний красный
dispatch. Красный кандидат 1e866291 не является находкой против #632: его
причина полностью внешняя (расхождение main/dev от другой задачи),
подтверждена логами CI, а не заявлением автора, и уже устранена.
Что проверено и корректно
- Трейлеры коммитов:
1fbf7704и10d32312несутIssue: #632,User-Visible: no— корректно, продуктового поведения нет (diff не трогаетsrc/**), changelog не требуется.оба коммита несут оба трейлера.$ git log --format='%H %s%n%b' origin/dev..HEAD -- scripts/task-packet.mjs test/task-packet.test.mjs scripts/mutation-registry.mjs - Класс файлов:
git diff origin/dev...HEAD --name-only— шесть файлов, всеdocs/**,scripts/**,test/**; ни одного файла класса A. Инфраструктурный трек (ускоренный вход) применён корректно. docs/reviews/INDEX.mdсвеж:node scripts/reviews-index.mjs --check→ «свеж», rc 0; счётчики «Документов: 1021, issue: 361» и строка#632 r2 · 🟢 · 0 · 0сгенерированы машиной, не вписаны руками — одно число, один источник (генератор), сверено прогоном, а не чтением.- Публикация
docs/reviews/CODE-REVIEW-632-r2.mdдословно соответствует вердикту, вынесенному в комментарии issue 2026-09-24T02:51:34Z (Вердикт: зелёный · заход r2 · … High: 0 · Medium: 0) — свереноgh issue view. - Validate зелёный на точном материале ревью:
SHA совпадает с
$ gh run view 35957716904 --json headSha,conclusion headSha 14396ed0b186dc9b883f0b26e460458828dcb58c conclusion successgit rev-parse HEAD— дешёвые гейты (tsc,npm test,npm run build+сверка бандла) подтверждены этим прогоном, повторно не гонял. - Промежуточный красный
1e866291разобран логами CI (раздел выше) — его единственная причина,workflow_sync/process.yml, не пересекается с диффом #632 и уже устранена.
Чего не проверял
npx tsc --noEmit/npm test(полный) /npm run buildсо сверкой бандла — не перегонял отдельно: зелёный Validate есть на точном SHA14396ed0(ссылка выше), дифф не касаетсяsrc/**. Точечно код и тесты задачи (node --test test/task-packet.test.mjs, мутанты) перепрогнал сам — см. выше.node scripts/check-docs.mjs— не применим, диф не трогаетsrc/**.npm run golden:verify, браузерные смоки,python -m pytest tests_backend,npm run invariants— не применимы: диф не меняет рендер, геометрию,custom_components/**/*.pyне тронут;node scripts/smoke-select.mjsдля этого диффа не запускал повторно — вывод «исполняемого frontend-диффа нет» дан в r2 на дельте, которая с тех пор не менялась (блобы идентичны), новых причин для другого ответа нет.- Живой
node scripts/task-packet.mjs --issue 612с реальнымgh— не запускал (ghв CI-раннере ревьюера доступен только для чтения issue и run-логов через уже настроенный токен, но полный сценарий с реальным API GitHub для входных данных скрипта не воспроизводил); эквивалентно проверено на уровнеbuildPacket()/тестов в r1/r2, логика сборки входов в этом раунде не менялась вовсе (блобы идентичны). - Полный лог упавшего
1e866291целиком (все job) не читал — только сводкуjobs[].conclusionи grep по причине упавшего шага; этого достаточно, чтобы отделить «эта причина не в скоупе #632» от «эта причина маскирует находку», поскольку сам факт и текст ошибки (process.yml в main и dev различаются) не пересекается с файлами #632.
Материал раунда
tree (14396ed0) — рабочая копия
blob c7bfebd2904fca3360b11eacedf9343d768e7915 scripts/task-packet.mjs
blob 15b9c04786b6733c8564c3173f700f374cc5b22d test/task-packet.test.mjs
blob f07f56b64e7b92b67b32654481b28e718788de6e scripts/mutation-registry.mjs
SHA материала ревью: 14396ed0b186dc9b883f0b26e460458828dcb58c
Предыдущий материал (r2, дельта от): b64bc932 (мёртв после ребейза; task-packet.mjs/test — те же блобы, см. выше; мутация-реестр перепроверен исполнением, не по блобу)
Вердикт
Зелёный. Дерево, за которое r2 уже выдал зелёный вердикт (High 0,
Medium 0), не изменилось: scripts/task-packet.mjs и
test/task-packet.test.mjs байт в байт совпадают с материалом r2; все
четыре мутанта задачи и весь тестовый файл перепрогнаны на текущем SHA и
зелёные. Красный промежуточный кандидат 1e866291 разобран по логам CI —
причина полностью внешняя к #632 (расхождение process.yml между main и
dev, вызванное другой задачей #634), устранена, дерево при переподписании
не менялось. Трейлеры, класс файлов, свежесть индекса — в порядке. Новых
находок нет. High: 0. Medium: 0. Задача готова к пред-релизной очереди.
Материал раунда
- Ветка:
issue/632-task-packet-track, коммит14396ed0b186— ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Дерево материала:
0d959028d35b205d556d2bf81ab5e2571128963egit log --all --format='%H %T' | grep 0d959028d35b - Тело issue:
85577dba6802882fd2cb7cc293044cd8318bc67981c0f743e27b5e77294bdece - Вердикт конвейера:
green· High 0