Перейти к содержанию

Ревью и вливание кода

Задача на код считается сделанной, когда её результат принят: ревью одобрено человеком и ветка влита. И то и другое — критерии приёмки самой задачи, которые объявляет её тип, а не отдельные задачи ревью и правок. Статья описывает, как это устроено для типа coding-task пакета selfdev, что видит ревьюер, что происходит при отказе и как исполнитель продолжает работу. Она для руководителей разработки, ревьюеров и администраторов установки. Обоснование — TAI-ADR-0053 и CP-ADR-0067 (амендмент В5–В9).

Как это устроено

sequenceDiagram
    autonumber
    participant A as Агент-исполнитель (демон)
    participant CP as Control Plane
    participant R as Ревьюер (человек)
    participant S as Исполнитель скиллов (git.merge@1)
    A->>CP: коммит на ветке task/<publicId>, публикация, succeed_run
    CP->>CP: попытка проверки: claim снят, зависимые недоступны
    CP->>R: gate-approval критерия review (approver из типа)
    alt approve
        R->>CP: approve
        CP->>S: git.merge@1 полномочиями ревьюера (основание — approval)
        alt merged: true
            CP->>CP: task.verified → done; зависимые доступны
        else conflict / branch_moved
            CP->>A: task.verification_failed, комментарий; задача в todo
        end
    else reject
        R->>CP: reject с комментарием
        CP->>A: task.verification_failed, комментарий; задача в todo
    end
    A->>CP: та же задача, та же ветка, «Замечания последней проверки» в prompt
  1. Исполнитель сдаёт задачу: демон коммитит работу на ветку task/<publicId>, публикует её в forge и завершает прогон с артефактом commit.
  2. Ядро открывает попытку проверки: claim снят, задачу нельзя взять, её зависимые не выдаются (task_not_ready) — они не начнутся на базе без предшественника.
  3. Критерий review (human) — ядро запрашивает gate-approval у ревьюера, объявленного типом.
  4. После одобрения критерий merge (deterministic) вызывает скилл git.merge@1: влить ровно одобренный коммит в целевую ветку.
  5. Оба пройдены — задача выполнена (task.verified, task.completed), зависимые становятся доступны.

Задача без опубликованного коммита (исполнитель ничего не изменил, публикация не удалась) пропускает оба критерия — у них условие when на $.task.artifact[commit].metadata.published — и становится выполненной сразу.

Критерии типа coding-task

acceptance:
  - key: review
    kind: human
    description: Ревью кода человеком …
    spec:
      approver: ${SELFDEV_REVIEWER_PRINCIPAL}
    when: ["$.task.artifact[commit].metadata.published"]
  - key: merge
    kind: deterministic
    description: Одобренный коммит влит в целевую ветку скиллом git.merge@1 …
    spec:
      skill: git.merge@1
      inputs:
        repository: "$.task.artifact[commit].metadata.repository!"
        branch: "$.task.artifact[commit].metadata.branch!"
        commit: "$.task.artifact[commit].metadata.commit!"
        target: "$.task.artifact[commit].metadata.targetBranch!"
        message: "Merge $.task.publicId!: $.task.title"
      expect: {merged: true}
    when: ["$.task.artifact[commit].metadata.published"]
  • Критерии принадлежат типу: задача не может их заменить (критерий задачи с ключом review или merge — 422 invalid_acceptance), только добавить свои.
  • merge — внешняя запись: ядро допускает её, только если раньше в той же попытке прошёл human с тем же when. Вызов идёт полномочиями ревьюера, решившего gate, с основанием authorizationBasis = {kind: approval, …}: влить ветку разрешил человек, а не агент, сдавший работу.
  • Ревьюер установки — переменная SELFDEV_REVIEWER_PRINCIPAL (UUID principal'а человека). Агент никогда не принимает собственную работу: решающим может быть только человек.

Общие правила критериев типа, when и внешней записи — в статье Типы задач и статусы.

Артефакт commit

Всё, что нужно ревьюеру и скиллу вливания, демон исполнителя кладёт в метаданные артефакта commit задачи:

Поле Значение
branch Ветка задачи task/<publicId>
commit Сдаваемый коммит
published Опубликована ли ветка в forge; false — смотреть нечего, критерии пропускаются
repository Адрес remote, куда опубликована ветка
targetBranch Куда вливать: ветка, от которой отведена рабочая копия (поле задачи baseBranch, например ветка фичи), иначе ветка по умолчанию зеркала
workspaceKey Ключ рабочей копии на хосте исполнителя

Ревьюер смотрит изменения от merge-base с целевой веткой: ветка могла быть отведена от старой базы, и в прямом git diff origin/<target> … свежие чужие коммиты выглядят как удаления.

git fetch origin
git diff $(git merge-base origin/<targetBranch> origin/task/<publicId>) origin/task/<publicId>

Решение ревьюера

  • Консоль — задача и её запрос решения видны в карточке задачи и на экране согласований; решение — кнопками (см. Консоль платформы).
  • Telegram — пакет notify присылает назначенному ревьюеру уведомление с кнопками «Одобрить» / «Отклонить» (см. Правила уведомлений).
  • Claude Code с плагином оператора — cp_list_approvals, затем cp_approve или cp_reject после явного решения человека (см. Повседневные сценарии).

Комментарий к отказу — главное, что получит исполнитель: пишите, что исправить.

Отказ и неудачное вливание

Что случилось Причина провала критерия Что дальше
Ревьюер отклонил approval_rejected у review Комментарий с решением ревьюера, задача в todo тому же исполнителю
Конфликт при вливании провал merge: reason: conflict (вывод git в details) Комментарий, задача в todo тому же исполнителю: подтянуть целевую ветку и разрешить конфликт
Целевая ветка сдвинулась во время вливания провал merge: reason: branch_moved Так же; повторная сдача запросит новое решение
Коммит уже влит merged: true, reason: already_merged Критерий пройден

Отдельных задач правок и вливания нет: вернувшаяся задача — та же задача, с тем же исполнителем, на той же ветке.

  • Замечания в prompt. Если последняя попытка задачи провалена, демон исполнителя перед прогоном читает её и добавляет в prompt блок «Замечания последней проверки»: номер попытки, результат каждого исполненного критерия, у проваленного — причина и комментарий ревьюера (см. Возврат исполнителю).
  • Та же ветка. Рабочая копия берёт ветку task/<publicId>: локальную, если она есть в зеркале, иначе опубликованную в forge (другой исполнитель, новое зеркало), и только если нет ни той, ни другой — новую от базы. Следующая публикация проходит без --force, а ревьюер видит новый коммит той же ветки.
  • Новое решение. Повторная сдача открывает новую попытку и запрашивает новое одобрение: решение прошлой попытки не засчитывается.
  • Третий провал подряд — задача в статусе категории blocked, дальше решает человек; демон исполнителя такую задачу не берёт.

Что нужно установке

Что Зачем
Пакет selfdev с типом coding-task и скиллом git.merge@1 Критерии приёмки и скилл вливания
SELFDEV_REVIEWER_PRINCIPAL в .env установки Кто решает review
Исполнитель скиллов с taimen_selfdev.git_merge:run в skills.local и правом skills.execute Кто исполняет git.merge@1 (например кодовый агент пакета)
Токен forge с правом записи в целевую ветку у исполнителя скиллов Скилл пушит результат вливания
У ревьюера — skills.invoke и tasks.write на задаче Вливание идёт его полномочиями
Пакет notify Уведомление ревьюеру о запросе решения

Прежняя схема ревью

Отдельный тип задачи ревью, который заводил демон исполнителя после успешного прогона (переменные CONTROL_PLANE_AGENT_REVIEW*, раздел workingCopy.review описания агента), и задачи «правки по ревью» из исхода approval в поставке больше не используются: демон такие задачи не заводит, а раздел workingCopy.review игнорирует с предупреждением в журнале. Открытые задачи прежнего типа ревью доводятся исходами approval их типа; после этого выведите тип из оборота (retire.TaskType файла установки).

Типичные проблемы

Симптом Причина Что делать
Задача сразу done, ревью не запрошено Нет опубликованного коммита: published: false или изменений не было — критерии skipped Проверить журнал демона (публикация ветки) и артефакт commit
Критерий review провален no_approver Нет человека, у которого запросить решение Задать SELFDEV_REVIEWER_PRINCIPAL (UUID человека) и опубликовать тип заново
merge провален no_decision Решение не прошло в этой попытке Проверить, что review одобрен именно в текущей попытке
merge провален с кодом прав У ревьюера нет skills.invoke / tasks.write или прав скилла Выдать права связке ревьюера
merge не выполняется долго, затем no_result Скилл никто не исполняет: нет исполнителя скиллов с git_merge:run Проверить описание исполнителя скиллов и его фактическое состояние
Зависимая задача не берётся Предшественник на приёмке (verification_pending) Решить ревью
Задача в blocked после трёх отказов Лимит попыток Разобраться и вернуть задачу в работу вручную

См. также