Агент-инженер по репозиторию · Модуль 5 · Урок 5.3

Структурное описание MR и идемпотентность

Зачем (какую проблему чиним)

Чтобы человек быстро и ответственно одобрил MR, ему нужно описание, на которое можно опереться: что сделано, зачем, как протестировано, какие риски. И вторая проблема: агента могут перезапустить (ретрай, повторный вебхук) — нельзя плодить дубли MR и оставлять мусорные ветки после неудач.

Решение и альтернативы

Решение: описание MR генерируется по шаблону из состояния задачи: Что (план/дифф), Зачем (issue/цель), Как протестировано (вердикт verify: какие проверки и их итог), Риски (что мог задеть, чего не покрыли тесты). Идемпотентность: перед созданием — FindPR(branch); если MR на эту ветку уже есть, обновляем, а не создаём второй. Неудачные попытки убираем: снять worktree, удалить брошенную ветку без MR.

Альтернативы: описание свободным текстом от модели — расплывчато, ревьюер не получает структуры рисков; ключ идемпотентности по времени/случайности — плодит дубли. Ключ по ветке задачи стабилен и естественен.

DIFF

Шаблон описания MR из состояния задачи и идемпотентное создание (find-or-update по ветке) + уборка неудачных попыток.

⚠ Безопасность

Раздел Риски в описании — часть human-in-the-loop: агент обязан честно перечислить, что мог задеть и чего тесты не покрывают, помогая ревьюеру, а не усыпляя его. Идемпотентность предотвращает шум и путаницу из дублей; уборка брошенных веток не оставляет «висячих» предложений изменений.

Проверка

MR содержит все четыре раздела, заполненные из реального состояния задачи (вердикт verify совпадает с прогоном). Повторный запуск на той же ветке обновляет существующий MR, а не создаёт второй; брошенная ветка без MR удаляется.

Глубже

Идемпотентность и устойчивость к ретраям — курс «Продакшн-разработка», Модуль 1 (durable execution, гл. 1); структурированный вывод и контракты — Модуль 4 (гл. 7).

mrbody.go: шаблон описания и идемпотентное создание (новый файл, фрагмент)
+// renderMRBody собирает структурное описание из состояния задачи.
+func renderMRBody(task Task, plan Plan, v Verdict, diffStat string) string {
+	return "## Что\n" + plan.summary() +
+		"\n\n## Зачем\n" + task.Issue +
+		"\n\n## Как протестировано\n" + verdictReport(v) + // build/tests/lint + итоги
+		"\n\n## Риски\n" + riskNotes(plan, diffStat) // что задето, чего не покрыли тесты
+}
+
+// openOrUpdateMR идемпотентен по ветке: не плодит дубли при ретраях/вебхуках.
+func openOrUpdateMR(ctx context.Context, f Forge, pr PullRequest) (string, error) {
+	if url, found, err := f.FindPR(ctx, pr.Branch); err != nil {
+		return "", err
+	} else if found {
+		return url, updatePR(ctx, f, pr) // обновляем существующий, не создаём второй
+	}
+	return f.CreatePR(ctx, pr)
+}

Anti-patterns

Грабли описания и идемпотентности
ГрабляПочему плохоКак правильно
Описание MR свободным текстом без структуры рисковРевьюер не видит, что задето и чего не покрыли тесты; ответственное одобрение затрудненоШаблон: Что / Зачем / Как протестировано / Риски — из реального состояния задачи
Создавать MR без проверки существующегоРетрай/повторный вебхук плодят дубли MRИдемпотентность: find-or-update по ветке задачи
Оставлять брошенные ветки/worktree после неудачМусор, висячие предложения изменений, путаницаУборка: снять worktree, удалить ветку без MR
Преувеличивать готовность в описанииУсыпляет ревьюера; ложное чувство безопасностиЧестный раздел Риски; вердикт verify приводится как есть

Практическое задание (RA-v4)

  • Сгенерировать описание MR по шаблону Что/Зачем/Как протестировано/Риски из состояния задачи и вердикта verify.
  • Сделать создание MR идемпотентным (find-or-update по ветке); убирать брошенные ветки/worktree.
  • Закоммитить: git commit -m "v4: structured MR body + idempotency".

Проверка знаний

Агента перезапустили по повторному вебхуку на той же ветке. Как не создать дубль MR?

  • A Генерировать случайный суффикс ветки на каждый запуск
  • B Идемпотентность по ветке: перед созданием искать существующий MR (FindPR) и при наличии обновлять его, а не создавать второй
  • C Создавать MR всегда — лишние закроет ревьюер
  • D Блокировать вебхуки