16 KiB
CODE-REVIEW-562-r1
Скоуп
Issue #562 «Process: отвязать роли и инфраструктурный трек от конкретных агентов» —
инфраструктурная задача (класс A не задет ни одним файлом): AGENTS.md,
PROCESS.md, scripts/process-gate.mjs, scripts/task-packet.mjs,
test/process-gate.test.mjs, test/task-packet.test.mjs. Материал ревью —
ровно 53f0635eddcd66346bca3bc2a92056d333ed1ca3 (единственный коммит впереди
origin/dev, merge-base = 9c08d583). Трейлеры: Issue: #562,
User-Visible: no — корректны, changelog не требуется и не тронут.
Заход r1, цикл 0/4.
Как проверялось
| Гейт | Результат | Источник |
|---|---|---|
npx tsc --noEmit |
зелёный | Validate на 53f0635e, https://github.com/Matysh/houseplan-card/actions/runs/34742978297 (переиспользован по указанию, не перегонялся) |
npm test (полный) |
зелёный, 2560/2559+1 skip | тот же прогон Validate |
npm run build + сверка бандлов |
зелёный | тот же прогон Validate |
node test/task-packet.test.mjs (таргетно) |
зелёный, 8/8 | прогнан в этом ревью |
node test/process-gate.test.mjs (таргетно) |
зелёный, 35/35 | прогнан в этом ревью |
node scripts/check-docs.mjs |
не запускался | diff не трогает src/** — правило §8 не требует |
смоки (demo/smoke_*.mjs) |
не запускались | diff не трогает demo/**/src/**; smoke-select по этому диффу тоже неприменим |
golden:verify |
не запускался | нет визуальных изменений |
pytest tests_backend |
не запускался | Python не тронут |
npm run invariants |
не запускался | геометрия не тронута |
Основная работа этого раунда — чтение диффа против origin/dev (git diff origin/dev...HEAD), сверка AGENTS.md/PROCESS.md с телом issue и
воспроизведение поведения scripts/task-packet.mjs (rightsFor) напрямую
через node -e, а не только чтением.
AC → как доказан
- AC1 (AGENTS.md/PROCESS.md/локальный CODEX-RUNBOOK.md не закрепляют роли
за Codex/Claude) — проверено чтением.
AGENTS.md:204иPROCESS.md:516,913упоминают Codex/Claude только как равноправные примеры «любой агент»;PROCESS.md:911-912называетanthropics/claude-code-actionтекущей технической реализацией ревьюера и прямо оговаривает, что это деталь автоматизации, а не закрепление роли. ЛокальныйCODEX-RUNBOOK.md(C:\Users\Admin\...) физически вне репозитория и вне материала ревью — не проверялся, проверить нечем. - AC2 (оба документа одинаково описывают маршруты S1–S8 и инфра-без-S →
S7 ↔ S6 → S8) — проверено чтением. Формулировка идентична по существу в
AGENTS.md(«Agent-neutral workflow») иPROCESS.md(§1, диаграмма §2, §9, блок §14). CODEX-RUNBOOK.md — не проверялся (вне репозитория). - AC3 (независимость автора/ревьюера, автоматическое ревью, автоматическое
слияние, прямое разрешение владельца на выпуск) — проверено чтением. §6 и
§10.4
PROCESS.md, соответствующий разделAGENTS.mdне тронуты по механике, только переформулированы; поведение конвейера (событие от метки, ребейз/слияние,S8-mergedпосле push) не изменилось. - AC4 (исторические документы ревью не переписаны) — доказано
git diff origin/dev...HEAD --stat:docs/reviews/**в диапазоне отсутствует.
Находки
Medium — task-packet.mjs определяет инфра-трек и право трогать класс A по тематической метке infra, а не по механическому критерию, и это противоречит соседнему модулю в том же диффе
-
Файл:
scripts/task-packet.mjs:29-30,36-38,49-51,115-117 -
Что не так:
rightsForиbuildPacketотносят issue к «инфраструктурному» треку и запрещают класс A по одному признаку — наличию меткиinfraвlabels. Но:PROCESS.md§9 (эта строка диффом не тронута) прямо называетinfraтематической меткой, ортогональной процессу, наравне сpolish,tests,docs,security,vacuum— то есть меткой, которая ничего не решает и может стоять на любой продуктовой задаче любого трека.- Механический критерий инфраструктурной задачи, который эта же задача
подтверждает и в
AGENTS.md, и вPROCESS.md§1, — «ни одного файла класса A в диапазоне», а не метка. scripts/process-gate.mjs:431-434(комментарий сохранён этим же диффом, не переписан) объясняет ровно это: «Исключение опирается на diff, а не на метку-разрешение: меткуinfraможно поставить продуктовой задаче и увести продуктовый коммит от проверки статуса». Реальный гейт (isInfrastructureRange) действительно смотрит только на классы файлов коммитов, не на метки issue.
task-packet.mjs— единственное место в этом диффе, которое читает меткуinfraкак источник правды об «инфраструктурности», и делает это ровно там, гдеprocess-gate.mjsв том же диффе объясняет, почему так делать нельзя. -
Воспроизведение (не только чтением — вызовом функции):
$ node -e "import('./scripts/task-packet.mjs').then(({ rightsFor }) => console.log(rightsFor('S6-in-progress', ['infra'])))" [ 'файлы класса A трогать НЕЛЬЗЯ; инфраструктурную реализацию МОЖНО вести сразу по issue (#562)', 'следующий шаг: gate:small + смоки по AC → push ветки → метка S7-code-review (метку после push)' ]По правилу №1 issue в
S6-in-progressразрешено трогать класс A — это единственный смысл статуса. Меткаinfra, по документированному §9 значению, орthogональна и не должна это отменять (пример: полноценная продуктовая задача с темой «инфраструктура/бэкенд», прошедшая полный S1→S8, помечена иS6-in-progress, и тематическиinfra— ничто в процессе такое сочетание не запрещает). Для такой задачиtask-packet.mjsвыдаёт заведомо неверный ответ на прямой вопрос «можно ли трогать класс A» — тот самый вопрос, ради которого инструмент существует (права выводятся из статусной метки по правилу №1, комментарий вtest/task-packet.test.mjs:13).Это не гипотетический контрпример: в репозитории уже есть открытые issue с меткой
infraодновременно со статуснойS*-меткой (#557S8-merged, #541S6-in-progress) — оба сейчас действительно инфраструктурные по содержанию, так что конкретно на них ответ инструмента случайно верен, но ничто в процессе не гарантирует, что продуктовая задача не получит ту же комбинацию меток. -
Почему это не поймали тесты: новый тест
test/task-packet.test.mjs:19-23проверяет толькоrightsFor(null, ['infra'])(статуса нет вообще) — счастливый путь, совпадающий с ментальной моделью автора. Нет ни одного теста наinfraвместе с реальнойS*-меткой, то есть ровно на тот случай, для которого модуль отвечает неверно. -
Серьёзность: Medium, в скоупе задачи (файл изменён этим же диффом). Не High:
task-packet.mjs— консультативный инструмент («источник правды остаётся GitHub и git: пакет ничего не пишет и ничего не решает», собственный комментарий модуля), реальный блокирующий гейт (process-gate.mjs, pre-push/CI) меткуinfraне читает и остаётся диффо-зависимым, так что ни один реальный push не будет пропущен или отклонён из-за этого дефекта. Риск — недостоверная подсказка агенту/человеку, читающему пакет задачи, вплоть до попытки продуктовой правки под видом инфраструктурной или наоборот отказа от легитимной правки класса A. -
Что чинить: либо не выводить «инфраструктурность» из метки
infraвовсе (использовать наличие/отсутствиеS*-метки как единственный предсказуемый по issue-данным сигнал — без диапазона коммитовtask-packetи так не может проверить класс файлов, значит стоит явно писать «трек неизвестен без diff» вместо утвердительного «нельзя/можно»), либо однозначно developed заново привязать «инфраструктурный трек» к отсутствиюS*-метки (что уже и так вычисляется какstatus === null), а не к меткеinfra, и добавить тест на комбинациюinfra+ реальныйS*.
Что проверено и корректно
- Единственный коммит в диапазоне, трейлеры
Issue: #562/User-Visible: noверны и соответствуют характеру изменения (документация процесса + два файла класса B, ни одного класса A). AGENTS.mdиPROCESS.mdсогласованно описывают продуктовый маршрутS1→S8и инфраструктурный `без S → S7-code-review ↔ S6-in-progress → S8-merged»; терминология («ускоренный вход», «accelerated entry») совпадает по смыслу в обоих документах.- Ни Codex, ни Claude не закреплены нормативно ни за одной ролью ни в
AGENTS.md, ни вPROCESS.md; единственное оставшееся упоминаниеanthropics/claude-code-actionявно помечено как деталь текущей автоматизации, а не правило. scripts/process-gate.mjs: правки — только текст сообщений/комментариев (замена ссылки#118→#562, уточнение формулировки); логикаisInfrastructureRange,checkIssueStatuses,statusOptionalне менялась и остаётся диффо-зависимой, как и было. Соответствующие тесты (test/process-gate.test.mjs) — тоже только переименования, проходят 35/35.docs/reviews/**не тронут — AC4 выполнено буквально.- Изменение не задевает
src/**,custom_components/**/*.py, i18n, манифесты — инфраструктурная классификация задачи верна механически.
Чего не проверял и почему
- Локальный
CODEX-RUNBOOK.mdвладельца — физически вне репозитория и вне материала ревью (SHA53f0635eего не содержит); проверить существование и содержание невозможно с этой стороны. Это ограничение AC1/AC2 для третьего документа, а не находка. node scripts/check-docs.mjs, браузерные смоки,golden:verify,pytest tests_backend,npm run invariants— не гоняны: diff не касаетсяsrc/**,demo/**, Python и геометрии, поэтому по §8 они не обязательны для этой задачи.- Полный
npx tsc --noEmit/npm test/npm run buildне перегонялись заново — переиспользован зелёный прогон Validate на этом самом SHA (ссылка выше), как разрешено инструкцией по этой задаче; вместо этого таргетно перегнаны оба изменённых test-файла напрямую. - Реальное использование
task-packet.mjsагентами на живых issue (кроме приведённого воспроизведенияrightsFor) — инструмент не входит в блокирующий гейт, поэтому эффект находки ограничен качеством подсказки, а не корректностью пайплайна; это отражено в оценке серьёзности как Medium, а не High.
Материал раунда
- SHA материала:
53f0635eddcd66346bca3bc2a92056d333ed1ca3 - Диапазон:
origin/dev(9c08d583)..HEAD, один коммit - Дерево: рабочая копия на этом SHA во время всего разбора
Материал раунда
- Ветка:
issue/562-agent-neutral-workflow, коммит53f0635eddcd— ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Дерево материала:
5eef2a99a76777df0a8642b5156e6755083e8f8egit log --all --format='%H %T' | grep 5eef2a99a767 - Тело issue:
520e2e2d0230ee82ee9e86795aa5e61e4172442aa24bea85a9429dd5aa7677ae - Вердикт конвейера:
yellow· High 0