Агент-инженер по репозиторию · Модуль 4 · Урок 4.2
Инструменты записи: edit_file/apply_patch и минимальный дифф
Зачем (какую проблему чиним)
Изоляция готова — теперь даём агенту писать внутри неё. Но «перезапиши файл целиком» — плохой инструмент записи: модель перегенерирует файл, теряя куски и раздувая дифф. Нам нужны точечные, структурированные правки с минимальным диффом — это и безопаснее (легче ревьюить), и дешевле.
Решение и альтернативы
Решение: инструмент edit_file принимает точную замену: старый фрагмент (anchor) → новый. Замена применяется, только если anchor найден ровно один раз (иначе ошибка — модель уточняет контекст). Для многофайловых правок — apply_patch в формате унифицированного диффа, применяемый строго в worktree. Обе операции вызывают assertWritable перед записью.
Альтернативы: write_file(path, content) целиком — модель теряет части файла, дифф огромен, ревью невозможно; построчные правки по номерам строк — хрупки (номера плывут после первой же правки). Замена по уникальному anchor — устойчива и даёт минимальный сфокусированный дифф.
DIFF
Добавляем edit_file (уникальная замена) и apply_patch; обе — только в worktree, через assertWritable, с возвратом получившегося диффа для самопроверки.
⚠ Безопасность
Каждая запись: (1) проходит assertWritable (не main, в worktree); (2) ограничена корнем worktree (safeJoin); (3) минимальна — anchor должен совпасть однозначно, иначе отказ. Минимальный дифф — это не только аккуратность: чем меньше и точнее изменение, тем реальнее человеческое ревью на версии v4.
Проверка
«Добавь проверку nil в функцию X» → edit_file меняет ровно нужные строки; git -C <wt> diff показывает минимальный сфокусированный дифф. Неуникальный anchor → отказ с просьбой уточнить контекст. Запись вне worktree/в main невозможна.
Глубже
Структурированные правки и инструменты записи кодинг-агентов — курс «Продакшн-разработка», Модуль 4 (специализированные агенты, гл. 8).
+// editFile заменяет ровно одно вхождение oldText на newText в файле внутри
+// worktree. Уникальность anchor гарантирует минимальный предсказуемый дифф.
+func (w *Workspace) editFile(ctx context.Context, rel, oldText, newText string) (string, error) {
+ if err := w.assertWritable(ctx); err != nil { // ИНВАРИАНТ перед записью
+ return "", err
+ }
+ abs, err := safeJoin(w.Dir, rel) // запись строго внутри worktree
+ if err != nil {
+ return "", err
+ }
+ src, err := os.ReadFile(abs)
+ if err != nil {
+ return "", err
+ }
+ if n := strings.Count(string(src), oldText); n != 1 {
+ return "", fmt.Errorf("anchor встречается %d раз (нужно ровно 1): уточните контекст", n)
+ }
+ out := strings.Replace(string(src), oldText, newText, 1)
+ if err := os.WriteFile(abs, []byte(out), 0o644); err != nil {
+ return "", err
+ }
+ return runGitWrite(ctx, w.Dir, "diff", "--", rel) // вернуть дифф для самопроверки
+}Anti-patterns
| Грабля | Почему плохо | Как правильно |
|---|---|---|
write_file(path, content) — перезапись файла целиком | Модель теряет куски при регенерации; гигантский дифф невозможно ревьюить | edit_file точечной заменой по уникальному anchor — минимальный дифф |
| Правки по номерам строк | Номера плывут после первой правки; последующие замены бьют не туда | Замена по содержимому (anchor), а не по позиции |
| Применять anchor, встречающийся несколько раз | Неоднозначность: правка уходит не в то место | Требовать ровно одно совпадение; иначе отказ с просьбой уточнить контекст |
Запись без assertWritable/safeJoin | Можно случайно записать в main или вне worktree | Каждая запись: инвариант «не main, в worktree» + ограничение корнем worktree |
Практическое задание (RA-v3)
- Реализовать
edit_file(уникальная замена по anchor) иapply_patch(унифицированный дифф) строго в worktree. - Вызывать
assertWritableиsafeJoinперед каждой записью; возвращать получившийся дифф. - Закоммитить:
git commit -m "v3: edit_file/apply_patch with minimal diffs".
Проверка знаний
Почему edit_file с заменой по уникальному anchor предпочтительнее write_file, перезаписывающего весь файл?
Верный ответ: B
B. Полная перезапись заставляет модель регенерировать файл (риск потери кусков) и порождает огромный дифф, который человек не может вдумчиво отревьюить. Точечная замена меняет ровно нужное — минимальный дифф, реальное ревью, ниже стоимость.