feat(process): a failed show verdict re-routes to ask without a fresh budget (#726)

A non-green show verdict that found "something to decide" went down the same
path as "fix the code": S6 with a limit of 2. Promoting the task to track:ask
was left to the agent's memory, with no named criterion and no trace, and the
exhausted budget only surfaced on the next S7 - after a fix nobody would read.

The structured verdict now carries `route` (fix | reclassify) and an optional
`criterion` (one of the six show criteria of PROCESS.md section 5). The trust
boundary reads a missing route as fix, rejects one outside the dictionary and
rejects reclassify on a green verdict. `reviewRoute` in process-track.mjs is
the single decision: on a code review of an unconfirmed show it moves the task
to track:ask and S3-spec; on an owner-confirmed show it adds `blocked` and asks
the owner; anywhere else reclassify degrades to fix with a note. The verdict
that spends the last cycle sets review-4 at once; the stage budget is shared
across tracks, so promotion changes the limit (4), not the count.

The "Решение по вердикту" step makes one `process-track.mjs route` call (from
dev, like the track step) and only executes its output: comment from a file,
labels from add/remove lists, status via status-label.mjs as before. The track
step also emits `confirmed` and a `route_note` for the review prompt; the
review document anchor gains a route tail that the old reader still parses;
wait-verdict reports the two new pipeline comments. The guard's own
spent >= limit check stays as the safety net.

Issue: #726
User-Visible: no
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
This commit is contained in:
Claude
2026-10-01 03:06:49 +00:00
committed by claude[bot]
parent 56be779ca7
commit d327ec3d93
14 changed files with 996 additions and 60 deletions
+53 -6
View File
@@ -539,6 +539,16 @@ patch-id кандидата слияния: вердикт к работе за
- Метка `review-4` ставится, когда исчерпан **бюджет циклов**; конвейер снимать
её не вправе — это решение владельца. Если бюджет пересчитан и оказался ниже
лимита, конвейер сообщает пересчёт, но метку не трогает.
- **Бюджет этапа один на все треки задачи** (#726). Повышение трека меняет
лимит, а не счёт: блокирующие вердикты прежних заходов остаются в бюджете
этапа, и после `show` → `ask` код-ревью продолжает тот же счёт с лимитом 4 —
на всех треках вместе не больше 4 циклов. Ревью ТЗ между ними — свой этап и
свой бюджет.
- **Вердикт, исчерпавший бюджет, сразу ставит `review-4`** (#726): шаг решения
по вердикту возвращает задачу (`S6-in-progress` или `S3-spec`) с меткой и
комментарием «Лимит циклов ревью исчерпан» — счёт, учтённые вердикты и
варианты ниже. Прежде об исчерпании говорил только следующий `S7`, после
правки, которую уже никто не прочтёт; его проверка осталась страховкой.
- **Исчерпание лимита — не «пятая попытка», а разбор.** Задача уходит владельцу,
решение одно из трёх:
1. **разделить** — issue закрывается как «заменён», вместо него 2–3 меньших с
@@ -618,12 +628,12 @@ patch-id кандидата слияния: вердикт к работе за
остаётся, риск уходит в пакетное ревью (§11.7). `visual` ship не повышает:
CSS-мелочь — законный ship. Выход за рамки повышает трек и при
подтверждённом `ship`, как прежде.
- На `show` риск — вопрос ревьюеру, маршрут не меняется: по каждому классу
ревьюер называет документ или AC, где поведение уже зафиксировано; не нашёл —
Medium «решать есть что — нужен `track:ask`» с названным критерием. `show`,
подтверждённый владельцем, ревьюер не повышает: вопрос уходит владельцу с
вариантом по умолчанию «повысить до `ask`». На `ask` ревьюер сверяет, что
каждый класс покрыт AC ТЗ.
- На `show` риск — вопрос ревьюеру, сам по себе трек он не меняет: по каждому
классу ревьюер называет документ или AC, где поведение уже зафиксировано; не
нашёл — вердикт с `route: reclassify` и названным критерием (#726, ниже).
`show`, подтверждённый владельцем, конвейер не повышает: `blocked` и вопрос
владельцу с вариантом по умолчанию «повысить до `ask`». На `ask` ревьюер
сверяет, что каждый класс покрыт AC ТЗ.
- Автор видит те же классы и их следствие в пакете задачи
(`node scripts/task-packet.mjs --issue NN`) до `S7`: пакет и конвейер читают
одно правило.
@@ -651,6 +661,18 @@ patch-id кандидата слияния: вердикт к работе за
рискованный участок повышает `ship` и требует от ревью `show` ссылки на
зафиксированное поведение.
На код-ревью `show` повышение исполняет конвейер (#726). Ревьюер возвращает не
зелёный вердикт с `route: reclassify` и `criterion` — идентификатором
невыполненного пункта подсказки выше: `complexity`, `surfaces`, `migration`,
`ux-contract`, `perf-touch`, `undocumented`. Шаг решения по вердикту ставит
`track:ask`, снимает `track:show` и переводит задачу в `S3-spec` комментарием:
критерий словами, документы код-ревью, бюджет. Код остаётся в ветке, полное ТЗ
пишется в теле issue, код класса A не пушится до `S5`; бюджет код-ревью не
обнуляется (§4). Подтверждённый владельцем `show` конвейер не повышает: задача
получает `blocked` и вопрос владельцу с вариантом по умолчанию «повысить до
`ask`». `reclassify` без критерия из списка, на `ask` или на ревью ТЗ —
обычный возврат с пометкой в комментарии.
**Что не меняется ни на одном треке:** issue и правило №1 (§1), трейлеры
коммитов, changelog для видимого изменения, зелёный Validate на точном SHA тега
беты (§8), гейты стабильного релиза. Качество держится на `dev` и на кандидате
@@ -791,6 +813,13 @@ issue #NN
Заход — номер прогона ревью, K — израсходованный бюджет §4: зелёные вердикты
его не тратят, поэтому заход и K расходятся, #227)
- **Закрытие:** `Выпущено в <тег беты> · CI: <ссылка> · Changelog: <ссылка>`
- **Маршрут вердикта** (пишет конвейер, #726): первой строкой «**Ревью show:
решать есть что — трек повышен до `track:ask`.**» либо «**Ревью show: решать
есть что — вопрос владельцу.**», последней — машинная
`<!-- hp:route <reclassify|owner-question> criterion=<id> -->`. Исчерпание
бюджета — первой строкой `Лимит циклов ревью исчерпан`, дальше счёт,
учтённые вердикты и варианты §4. Маршрут, не применённый к вердикту, —
строка «маршрут reclassify не применён: <причина>».
**Вперёд двигает только зелёный вердикт.** Жёлтый и красный возвращают автору;
разница между ними содержательна для человека, но не для маршрута. Первая
@@ -1195,6 +1224,7 @@ SHA. Manifest публикуется и входит в `SHA256SUMS`; свежа
```
S4-spec-review → ревью ТЗ → S5-ready либо возврат в S3-spec
S7-code-review → код-ревью → слияние в dev → S8-merged либо возврат в S6-in-progress
(show, route: reclassify → S3-spec, #726)
```
Текущая техническая реализация независимого ревьюера —
@@ -1266,6 +1296,23 @@ limit`) и своей логики трека не держит; ответ comp
больше инфраструктуру не доказывает — `ask`, лимит 4. Этап `spec`, отсутствие
ветки и инфраструктурный дифф дают пустой риск и прежнее поведение.
**Маршрут вердикта** (#726). Структурный вердикт модели — `verdict`, `high`,
`medium`, `summary`, `route` (`fix` | `reclassify`, обязательное в схеме) и
необязательный `criterion`. Граница доверия (`scripts/review-result-gate.mjs`)
читает отсутствующий `route` как `fix`, отвергает значение вне словаря и
`reclassify` при зелёном вердикте: результат противоречив, модель не
перезапускается. Смысл `criterion` судит шаг «Решение по вердикту»: **один
вызов** `process-track.mjs route` по вердикту, треку и его подтверждению
владельцем (выход шага трека), бюджету guard и текущим меткам; статус, метки и
тело комментария (файлом) — из выхода скрипта. Метки трека, `blocked` и
`review-4` ставит `gh issue edit` по этому выходу, статус — `status-label.mjs`,
как прежде. Шаги без модели (`ship` в рамках, повторно применённый зелёный)
скрипт не зовут. Заметку маршрута в промпт даёт шаг трека: на код-ревью `show` —
поля и список критериев §5, иначе `route: fix`. Документ ревью несёт маршрут
хвостом строки якоря — «Вердикт конвейера: `yellow` · High 0 · маршрут
`reclassify` (критерий `undocumented`)», — сводка прогона печатает маршрут и
бюджет после вердикта.
| | `ship` | `show` | `ask` |
|---|---|---|---|
| Validate на материале | лёгкий; годится завершённый push-прогон на этом SHA | лёгкий, как у `ship` | лёгкий, как у `ship` (#709) |