17 KiB
CODE-REVIEW-562-r2
Скоуп
Issue #562 «Process: отвязать роли и инфраструктурный трек от конкретных агентов», заход r2, блокирующих циклов израсходовано 1/4 до этого раунда.
Материал ревью — ровно 8f000dd459393cd0d17e9cfa58513a68f7f5ffa1 (рабочая
копия уже на нём). Полный диапазон против dev: origin/dev(9c08d583)..HEAD
(два содержательных коммита — 53f0635e разобран и получил жёлтый вердикт в
r1, 8f000dd4 — правка этого раунда; 00ac0875 — только документ r1).
Раунд не первый и предыдущий вердикт был жёлтым (Medium в скоупе), поэтому по
PROCESS.md §2.9 разбор ведётся по дельте: находка r1 плюс всё, до чего дельта
дотягивается, а не полный повторный прогон. Дельта раунда — ровно
53f0635e..8f000dd4:
scripts/task-packet.mjs | 16 +++++++++++-----
test/task-packet.test.mjs | 17 +++++++++++++++--
2 files changed, 26 insertions(+), 7 deletions(-)
Это не ребейз (родитель тот же dev-merge-base 9c08d583, что и в r1),
контракт поведения затронут ровно там же, где была находка r1, новая
подсистема не задета — сокращение объёма законно.
Трейлеры коммита 8f000dd4: Issue: #562, User-Visible: no — верны
(правка внутри scripts/** и test/**, класс A не тронут, changelog не
нужен и не тронут).
Как проверялось
| Гейт | Результат | Источник |
|---|---|---|
npx tsc --noEmit / npm test (полный) / npm run build + сверка бандлов |
зелёный | Validate на 8f000dd4, https://github.com/Matysh/houseplan-card/actions/runs/34743589488 (переиспользован по инструкции, не перегонялся) |
node --test test/task-packet.test.mjs (таргетно, по дельте) |
зелёный, 9/9 | прогнан в этом ревью |
Тест на старом коде (53f0635e) с тем же файлом теста |
красный, 2/9 | прогнан в этом ревью через git worktree — доказывает, что новый негативный тест умеет падать (см. находки закрытия r1 ниже) |
node scripts/smoke-select.mjs --base 53f0635e --head 8f000dd4 |
«Исполняемого frontend-диффа нет... Тронуто файлов: 3» | прогнан; смоки не выбираются — диффу нечего проверять браузером |
node scripts/check-docs.mjs |
не запускался | дельта не трогает src/** |
golden:verify, pytest tests_backend, npm run invariants |
не запускались | нет визуальных/Python/геометрических изменений |
Закрытие раунда r1
| Находка r1 | Чем закрыта | Где это видно |
|---|---|---|
Medium — task-packet.mjs определял «инфраструктурный» трек и запрет класса A по тематической метке infra, а не по механическому критерию из process-gate.mjs, из-за чего продуктовая задача с меткой infra + S6-in-progress получала неверный ответ «класс A трогать нельзя» |
rightsFor больше не читает infra из labels вообще — трек передаётся явным параметром { infrastructure }; buildPacket вычисляет его из branch.infrastructure, а тот в collectInputs — из реального diff base..ref через переиспользованный classify() из process-gate.mjs (тот же критерий, что у блокирующего гейта) |
scripts/task-packet.mjs:22,27,30,110-121,209-210; воспроизведение — node -e "rightsFor('S6-in-progress', ['infra'])" теперь возвращает 'продуктовый код трогать МОЖНО', а не запрет |
(следствие) отсутствие теста на комбинацию infra + реальная S*-метка |
новый тест test/task-packet.test.mjs:112-120 явно бьёт labels: ['infra', 'S6-in-progress'] и требует track === 'полный' + разрешение на класс A |
проверено запуском теста против кода r1 (53f0635e) — падает с AssertionError: expected 'полный', actual 'инфраструктурный', то есть тест действительно ловит старый баг, а не проходит тавтологически |
Находка r1 закрыта полностью для того сценария, для которого была написана
(ложное «нельзя» для помеченной infra продуктовой задачи). Дельта, однако,
меняет ещё одну ветку того же кода (как трек вычисляется, когда ветки ещё
нет) — это и есть новая находка этого раунда, см. ниже.
Унаследовано из r1
Приняты без повторной проверки (дельта этого раунда их не касается):
- AC1 (роли не закреплены за Codex/Claude в
AGENTS.md/PROCESS.md; локальныйCODEX-RUNBOOK.mdвне материала) и AC2 (оба документа одинаково описывают маршруты S1–S8 и инфра-без-S → S7 ↔ S6 → S8) —AGENTS.mdиPROCESS.mdдельтой8f000dd4не тронуты вовсе (диф ограниченscripts/task-packet.mjsиtest/task-packet.test.mjs). Документ:docs/reviews/CODE-REVIEW-562-r1.md, SHA53f0635e. - AC3 (независимость автора/ревьюера, автоматическое ревью и слияние,
разрешение владельца на выпуск) — механика конвейера этой дельтой не
затронута. Документ: тот же, SHA
53f0635e. - AC4 (исторические документы ревью не переписаны) — дельта
8f000dd4не касаетсяdocs/reviews/**(см.git show --stat 8f000dd4в скоупе выше — толькоscripts/иtest/). Документ: тот же, SHA53f0635e. scripts/process-gate.mjsиtest/process-gate.test.mjs— не изменены этой дельтой (последний раз правились в53f0635e, только переименования сообщений/ссылки на issue); логикаisInfrastructureRangeне тронута. Документ: тот же, SHA53f0635e.
Находки
Medium (в скоупе) — после фикса статусless infra-issue без опубликованной ветки получает заведомо неверную подсказку «вне процесса, ждать S-метку владельца»
-
Файл:
scripts/task-packet.mjs:118(const infrastructure = branch?.infrastructure === true;) иscripts/task-packet.mjs:39-51(rightsFor, веткаdefault). -
Что не так: новый критерий полностью корректен, когда ветка уже опубликована и
collectInputsуспел посчитать diff. Но пока ветки наorigin/issue/NN-*ещё нет (refs[0]пуст вcollectInputs),branchостаётсяnull, иinfrastructureтеперь всегдаfalse— старый путь черезlabels.includes('infra'), который умел ответить верно даже без ветки, убран целиком, а альтернативы для случая «ветки ещё нет» не появилось.Это ровно момент, для которого сама задача #562 вводит ускоренный трек: «Инфраструктурная задача выполняется сразу... без стадий S1–S6 до первого хендоффа. По готовности ветка публикуется» (тело issue). И это ровно прописанный сценарий использования инструмента:
AGENTS.md:378— «Start a task from its packet... node scripts/task-packet.mjs --issue NN» — команда, которую в первую очередь запускают при взятии задачи, то есть до того, как какая-либо ветка опубликована. -
Воспроизведение:
$ node -e "import('./scripts/task-packet.mjs').then(({ buildPacket }) => console.log(buildPacket({ issue: { number: 999, title: 'infra no branch yet', state: 'OPEN', url: 'u', body: '' }, labels: ['infra'], })))" track: полный rights: [ 'продуктовый код трогать НЕЛЬЗЯ: статус не S5/S6/S7 (правило №1)', 'статусной метки нет — продуктовая задача вне процесса; вход — первая S*-метка владельца' ]На коде r1 (
53f0635e) тот же вызов давал верный ответ:track: инфраструктурный rights: [ 'файлы класса A трогать НЕЛЬЗЯ; инфраструктурную реализацию МОЖНО вести сразу по issue (#562)', 'инфраструктурный вход: реализовать и проверить → push ветки → S7-code-review; ТЗ и S1–S6 не нужны (#562)' ]Это регресс, внесённый именно правкой этого раунда, а не унаследованная проблема: до
8f000dd4тот же вход обрабатывался верно. -
Почему это не поймал новый тест: оба новых/изменённых теста этого раунда (
test/task-packet.test.mjs:20-24,112-120) передаютbranchявным объектом с уже посчитаннымinfrastructure. Ни один тест не вызываетbuildPacket/rightsForдля statuslessinfra-issue безbranch— то есть без ветки, что и есть штатное состояние в момент «взять задачу и вызвать пакет». -
Серьёзность: Medium, в скоупе (файл и тест изменены этим же диффом). Не High:
task-packet.mjs— консультативный инструмент, ничего не решает и не блокирует ни один реальный push; блокирующий гейт (process-gate.mjs) метку не читает и этой правкой не затронут. Риск — неверная подсказка ровно в момент, когда агент решает, можно ли начинать инфраструктурную реализацию без S-метки: вместо разрешения «делай сразу» пакет теперь говорит «жди S-метку от владельца», что для инфра-трека прямо противоречит тексту issue #562 иPROCESS.md. -
Что чинить: для случая без ветки не возвращать уверенное «вне процесса» — либо явно писать неопределённость («трек не подтверждён без diff опубликованной ветки; по метке
infraпохоже на инфраструктурный»), либо (эквивалент предложения r1, вариант «привязать трек к metки без diff», применённый только к before-branch состоянию) при отсутствии ветки временно доверятьlabels.includes('infra')как единственному доступному сигналу, но маркировать его в выводе как непроверенный diff'ом, а не как решённый факт.
Что проверено и корректно
- Находка r1 закрыта именно так, как и была сформулирована:
task-packet.mjsдля мисклассифицированной продуктовой задачи (infra+ реальнаяS6-in-progress) больше не запрещает класс A — трек и права теперь выводятся из того же механического критерия (classify()изprocess-gate.mjs), что и у блокирующего гейта, а не из темы issue. - Новый тест
#562: the infra label alone never grants the accelerated track— не тавтологичен: проверено падением на снапшоте53f0635e(AssertionError, 2 упавших теста из 9). - Тесты дельты: 9/9 зелёных на
8f000dd4. - Трейлеры
Issue: #562/User-Visible: noверны; класс A не тронут; changelog не требуется и не тронут — соответствует характеру правки. docs/reviews/**этой дельтой не тронут — AC4 остаётся выполненным.smoke-selectподтверждает: diff не задеваетsrc/**/demo/**, браузерные смоки этому раунду не нужны.
Чего не проверял и почему
- Полный
npx tsc --noEmit/npm test/npm run buildне перегонялись — переиспользован зелёный Validate на этом самом SHA8f000dd4(ссылка выше); вместо этого таргетно перегнан изменённый тестовый файл и его же версия на предыдущем SHA (для проверки «тест умеет падать»). AGENTS.md,PROCESS.md, локальныйCODEX-RUNBOOK.md— не перечитывались заново: дельта раунда их не трогает (см. «Унаследовано из r1»).check-docs, browser-смоки,golden:verify,pytest tests_backend,npm run invariants— не запускались: дельта ограниченаscripts/**иtest/**, ниsrc/**, ниdemo/**, ни Python, ни геометрия не тронуты.- Реальное поведение
scripts/process-gate.mjs(блокирующий гейт) — не перепроверялось: этой дельтой файл не изменён, вывод r1 (диффо-зависимый, меткуinfraне читает) остаётся в силе.
Материал раунда
- SHA материала:
8f000dd459393cd0d17e9cfa58513a68f7f5ffa1 - Дельта раунда:
53f0635eddcd66346bca3bc2a92056d333ed1ca3..8f000dd459393cd0d17e9cfa58513a68f7f5ffa1(2 файла, 26 строк) - Полный диапазон против
dev:origin/dev(9c08d583)..HEAD - Дерево: рабочая копия на этом SHA во время всего разбора
Материал раунда
- Ветка:
issue/562-agent-neutral-workflow, коммит8f000dd45939— ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Дерево материала:
36ef122f5778df5144077d79a3584a54a421ee1egit log --all --format='%H %T' | grep 36ef122f5778 - Тело issue:
520e2e2d0230ee82ee9e86795aa5e61e4172442aa24bea85a9429dd5aa7677ae - Вердикт конвейера:
yellow· High 0