12 правил code-review с AI: что мы разрешаем команде 42 РМ, а что нет
У клиента — продуктовой компании на 42 рабочих места — команда разработки 12 человек активно использует AI-помощников Claude Code, GitHub Copilot и Cursor уже 9 месяцев. За это время мы собрали статистику по PR-ревью: 412 пулл-реквестов с AI-участием, 38 живых багов на стейдже, 7 инцидентов на проде. Этот опыт сформировал 12 правил, которые сегодня живут в виде CODEOWNERS-файла и pre-commit hooks в их репозиториях. Делюсь правилами вместе с примерами реальных ошибок, которые они ловят, и стендом, на котором мы прогоняем AI-код перед мерджем.
Контекст: 9 месяцев работы и что мы реально собрали
Клиент пришёл к нам осенью прошлого года с запросом «помогите оптимизировать процесс разработки, программисты слишком долго рутинятся на простых задачах». Они уже пробовали GitHub Copilot полгода до нас, но без правил — и за это время на проде словили два инцидента: один с SQL-инъекцией в endpoint поиска контрагентов, второй с молчаливым проглатыванием ошибки в обработчике платежей. После этого собрались, и я предложил завести структурированный подход — не запрещать AI, а описать границы.
За 9 месяцев команда сделала 412 PR-ов, в которых хотя бы 30% строк было сгенерировано через AI-помощника (это видно по комментариям в коде и логам Cursor/Claude). На этой выборке я выделил три типа ошибок, которые повторялись чаще всего, и составил на основе них классификатор для CODEOWNERS-бота.
Цифры по типам ошибок
Тип 1 — «галлюцинации API»: AI вызывает несуществующий метод библиотеки или возвращает функцию, которой нет в установленной версии. У нас 47 случаев за 9 месяцев, из них 31 поймал линтер ещё до коммита, 14 — pre-commit hook, 2 — code review. Тип 2 — «небезопасный SQL и shell»: конкатенация строк вместо параметров, чтение из субшелл-команды без экранирования. 23 случая, из них 17 поймал semgrep, 6 — ревьюер. Тип 3 — «лень в обработке ошибок»: голый except Exception без логирования, return None вместо raise. 38 случаев, ловятся только людьми и линтерами с кастомными правилами.
Правила 1-4: что AI имеет право писать сам
Я разбил все правила на четыре блока по три правила в каждом. Первый блок — про доверенные области, где AI может писать самостоятельно с минимальным контролем. Это типовые CRUD-операции, юнит-тесты по существующим тестовым шаблонам, и форматирование/миграция кода (переименования, перенос файлов, перевод с одного фреймворка на другой в рамках одного языка).
Правило 1: «AI пишет CRUD по существующей модели». Если у нас есть SQLAlchemy-модель Contract и нужны стандартные GET/POST/PUT/DELETE-эндпоинты — AI справится за минуты, и это безопасно: модель уже валидируется, схема пермишенов наследуется, тесты пишутся по шаблону. Правило 2: «AI пишет юнит-тесты только когда задано pytest-шаблон от человека». Тесты от AI должны проходить ровно тот контракт, который зафиксирован руками — иначе AI начинает «улучшать» поведение под тесты.
Правило 3 и 4 — где AI выручает на нудятине
Правило 3: «AI делает массовые рефакторинги по чёткому промпту». Например, переименовать поле user_id в owner_id по всему коду — это идеальная задача для AI: занудно, требует точности, легко проверяется через git diff. У нас за полгода так провели 19 переименований и 4 миграции между фреймворками (например, перевод старого django-rest на FastAPI для нового сервиса). Правило 4: «AI пишет docstrings и комментарии к существующему коду». Здесь AI хорош: он внимательно читает реализацию и описывает её человеческим языком, ошибок почти не делает.
Правила 5-8: что AI пишет только под надзором
Второй блок — это «серая зона». Здесь AI может писать, но только в режиме «pair programming»: разработчик садится рядом, проверяет каждый шаг, и не оставляет AI без присмотра больше 15-20 минут. Сюда входят бизнес-логика (правила расчётов, обработчики платежей, интеграции с внешними API) и работа с базой данных (SQL-запросы, миграции, оптимизации).
Правило 5: «Бизнес-логика с деньгами — только pair programming». На проде у клиента есть три endpoint'а, которые работают с тарифами и платежами. AI имеет право предлагать код, но коммит делает только живой разработчик, и в commit-message обязательно проставляется тег [pair-with-claude]. Это даёт нам в Git Blame чёткую разметку, к каким коммитам подходить с особым вниманием на ревью.
Правило 6 — SQL и работа с данными
Правило 6: «Любой SQL-запрос на больше 50 строк проверяется ручным EXPLAIN». AI охотно генерирует JOIN-ы, которые выглядят правильно, но в плане выполнения превращаются в Hash Join 200 миллионов строк против справочника. У нас был случай в феврале: AI написал отчёт по контрагентам, который на тестовых 1 000 записях работал за 0,3 секунды, а на проде на 280 000 записях — за 47 секунд и подвисал на блокировке. Ревьюер сделал EXPLAIN ANALYZE, нашёл недостающий индекс, починили за 20 минут.
# pre-commit hook — semgrep + кастомные правила
# .pre-commit-config.yaml
repos:
- repo: https://github.com/returntocorp/semgrep
rev: v1.96.0
hooks:
- id: semgrep
args: ['--config=.semgrep/ai-rules.yaml',
'--error', '--quiet', '--strict']
files: \.(py|sql|js|ts)$
# .semgrep/ai-rules.yaml — наши кастомные правила
rules:
- id: no-fstring-sql
pattern: $DB.execute(f"...{$X}...")
message: "Запрещён f-string в SQL — параметризуй через $1, %s или :name"
languages: [python]
severity: ERROR
- id: no-bare-except
pattern: |
try:
...
except:
...
message: "Запрещён голый except — лови конкретный класс ошибки"
languages: [python]
severity: ERROR
- id: no-eval-exec
pattern-either:
- pattern: eval(...)
- pattern: exec(...)
message: "Запрещён eval/exec в продакшн-коде"
languages: [python]
severity: ERROR
Правило 7: «Миграции базы пишет человек, AI только помогает с шаблоном». В alembic-миграциях у нас был случай, когда AI предложил DROP COLUMN на полном merge-сценарии, и если бы это попало на прод, потеря данных была бы необратимой. С тех пор любая alembic-миграция в этом репозитории помечается @migration-by-human, и без этого CI-бот её блокирует. Правило 8: «Интеграции с внешними API — AI пишет skeleton, но обработчик ошибок и таймауты добавляет человек». Здесь главная боль — AI обожает писать requests.get(url).json() без обработки 502, 504 и таймаутов.
Правила 9-12: что AI трогать категорически нельзя
Третий блок — это запреты. Здесь у меня жёсткая позиция: я к AI вообще не подхожу, сажусь сам и читаю код. К этим зонам относятся аутентификация и пермишены, обработка платежей (не бизнес-правила, а собственно интеграции с банками и эквайрингом), персональные данные клиентов (152-ФЗ), и production-инциденты.
Правило 9: «Аутентификация и сессии — никакого AI». В прошлом году в индустрии было 12+ публичных инцидентов, когда AI-сгенерированный код проверки токена пропускал просроченные сессии или принимал пустой Authorization-header за валидный. Я считаю это перегибом со стороны AI-помощников — они слишком охотно «упрощают» проверки. Правило 10: «Загрузка/обработка файлов от пользователей — только человек, и с песочницей». AI любит писать pickle.load(uploaded_file) без проверки, что это вообще не RCE-вектор.
Правила 11 и 12 — про инциденты и легаси
Правило 11: «На инциденте production не зовём AI». Когда у клиента упал endpoint оплаты в марте, дежурный разработчик попытался диагностировать через Claude. Claude выдал три гипотезы, каждая выглядела убедительно, но ни одна не была верной — реальная причина была в неожиданной миграции схемы у платёжного провайдера. Потеряли 40 минут на гипотезы AI, пока я не написал «закрой Claude и читай stack trace». Правило 12: «Рефакторинг легаси-кода старше 18 месяцев — только с написания тестов». На старом коде AI любит «упрощать», теряя пограничные случаи, которые когда-то добавлял прежний разработчик после конкретной аварии.
Наш чек-лист на PR-ревью: 11 пунктов
Из правил вырос чек-лист, который у клиента сейчас живёт как PULL_REQUEST_TEMPLATE.md в каждом репозитории и проверяется CI-ботом перед открытием ревью. 11 пунктов, каждый ставится в [x] или [ ] разработчиком, а CI проверяет их по факту. Если хотя бы один пункт не отмечен — PR не открывается на ревью.
# PULL_REQUEST_TEMPLATE.md в каждом репозитории
## Контекст
- Задача в Jira: [PROJ-XXXX](https://jira.example.com/...)
- Использовался ли AI-помощник: [ ] нет [ ] частично [ ] >50% кода
- Если AI — какой: [ ] Claude Code [ ] Cursor [ ] Copilot
## Чек-лист перед ревью
- [ ] semgrep + bandit прошли без ошибок
- [ ] нет dynamic SQL, eval, exec, pickle.load
- [ ] нет голых except: Exception
- [ ] нет N+1 запросов в ORM (проверь django-debug-toolbar)
- [ ] миграции идемпотентны и обратимы
- [ ] логирование на ошибках (logger.exception на except)
- [ ] секреты не в коде, только из settings/env
- [ ] юнит-тесты написаны от руки (не AI), покрытие >70%
- [ ] прогнан ai-sandbox: docker compose up, тесты PASS
- [ ] нет дублирования логики с существующими модулями
- [ ] proof of human review: я прочитал каждую строку
Последний пункт — про «proof of human review» — у нас живёт как договорённость, а не как технический контроль. Невозможно автоматически проверить, что разработчик прочитал каждую строку. Но в команде клиента живёт правило: если на ревью находится ошибка, которая «выпала из AI», и автор PR не пометил pair-with-claude, — это считается личной ошибкой автора, а не общей. За полгода это сильно дисциплинировало ребят.
Стенд для тестирования AI-кода: изолированный Docker
В дополнение к pre-commit hooks и чек-листу у нас на сервере клиента развёрнут отдельный стенд под названием ai-sandbox. Это копия prod-стека в Docker Compose: Postgres 16, Redis 7, Python 3.12, Node 20, RabbitMQ 3.13, MinIO для S3-эмуляции. Данные внутри — обезличенные: мы один раз прогнали скрипт, который заменил все email/телефоны/имена на синтетические через Faker, а финансовые суммы умножил на случайный коэффициент 0,2-5.
Когда разработчик пишет фичу с AI, перед отправкой PR на ревью он обязан прогнать тесты на ai-sandbox локально через docker compose up + pytest. CI потом перепрогоняет то же самое в чистом контейнере. Это занимает 8-15 минут на типовом PR, но в 11 случаях за полгода поймало баги, которые в обычной разработке вылезли бы только на стейдже. Особенно ценно для багов в подписках и периодических задачах — на ai-sandbox у нас можно «прокрутить» 7 дней за 3 секунды через подмену time.time().
Затраты на содержание стенда
Стенд ai-sandbox живёт на отдельной VM у клиента — 16 vCPU, 32 ГБ RAM, NVMe 500 ГБ — это около 8 000 ₽ в месяц на хостинге Selectel + 4 часа моего времени в месяц на поддержку и обновления (новые версии Postgres, ребейслайн обезличенных данных раз в квартал). По нашей внутренней статистике, один пойманный AI-баг экономит 3-8 часов работы разработчика + 1-2 часа QA-инженера. За 6 месяцев стенд окупил себя в 7-9 раз.
Результат за 9 месяцев — конкретные цифры
До нас у клиента было 4-5 багов на прод в неделю, после внедрения правил — 1-2. Время на code-review выросло с 22 минут до 28-31 минуты на PR (это минус, но окупается). Количество отвергнутых PR упало с 18% до 6% — потому что разработчики стали учитывать правила ещё на этапе написания. Скорость доставки новых фич выросла на 31% по замерам Jira за 6 месяцев — благодаря тому, что AI берёт на себя нудятину.
Что важнее всего — у клиента изменилось отношение к AI в команде. Раньше было «AI делает магию, мы коммитим». Теперь — «AI это инструмент, как Resharper или git: помогает, но проверять надо». Один из senior-разработчиков сказал мне на встрече в апреле: «Я наконец перестал бояться, что мне AI заменит — он мне теперь экономит часа полтора в день на рутинных задачах, и я могу заняться архитектурой».
FAQ: что чаще всего спрашивают клиенты
В чём AI-помощники реально ошибаются на корпоративном коде?
По нашей статистике за 9 месяцев на команде из 12 разработчиков — три типа ошибок дают 78% инцидентов. Первый — выдуманные API: Claude или Copilot пишут вызов несуществующего метода библиотеки, и код не компилируется (а в Python падает в рантайме). Второй — небезопасные SQL-запросы с конкатенацией строк вместо параметризованных, мы такое 14 раз ловили на PR-review. Третий — лень в обработке ошибок: AI охотно делает try-except Exception без логирования, после чего боевая ошибка молча проглатывается.
Можно ли вообще доверять AI-помощникам безопасно?
Доверять — нет, использовать с правилами — да. У нас есть три уровня контроля. Первый — список запретов в репозитории клиента (никаких dynamic SQL, никаких eval/exec, никаких чтений секретов из окружения без через секрет-менеджер). Второй — обязательный набор pre-commit hooks с semgrep и bandit, которые ловят 40-60% типовых проблем до review. Третий — человек-ревьюер на каждый PR, и в AI-проекте это правило ужесточается: ни одна строка от AI не попадает в main без живого человека на ревью.
Сколько у вас занимает code-review PR с AI-кодом против PR от человека?
По замерам у клиента — на 15-25% дольше, но это не приговор. Live-разработчики команды клиента в среднем тратят 22 минуты на ревью PR в 200 строк изменений. На PR-ах с AI-кодом — 28-31 минуту. Причина не в том, что AI пишет хуже, а в том, что я не могу полагаться на интуицию ревьюера «этот разработчик такого не написал бы». На AI-коде нужно проверять каждый необычный паттерн руками. Хорошая новость — это окупается: количество багов на проде упало с 4-5 в неделю до 1-2.
Чем у вас разработчики пишут — Claude, Copilot или Cursor?
У клиента в команде 12 разработчиков, после полугодового пилота они разбились на три группы. 5 человек сидят на Claude Code (Sonnet 4.5 → Opus 4.6 → 4.7) — это люди, которые пишут на Python и Go большие куски логики и предпочитают разговорный стиль. 4 человека выбрали Cursor с переключением между моделями — они работают с фронтом на React/TypeScript и любят быстрые подсказки в редакторе. 3 разработчика на 1С остались с GitHub Copilot — он хорошо тренирован на проектах из открытого кода, и для типовых паттернов 1С его подсказки достаточны.
Как у вас выглядит изолированный стенд для тестирования AI-кода?
У нас на сервере клиента есть отдельная Docker-среда с приставкой «ai-sandbox». Это копия prod-стека (Postgres 16, Redis 7, Python 3.12, Node 20) с обезличенными данными (мы заменили все email/телефоны/имена через скрипт-сanitizer на синтетические из библиотеки Faker). Когда разработчик пишет фичу с AI, перед отправкой PR на ревью он обязан прогнать тесты на ai-sandbox и приложить логи. Это занимает 8-15 минут, но в 11 случаях за полгода поймало баги, которые в обычной разработке вылезли бы только на стейдже.
Итог
AI-помощник на корпоративном проекте — это не вопрос «разрешать или нет», а вопрос «как описать границы». 12 правил, чек-лист на PR и стенд ai-sandbox дают клиенту минус 70% багов на проде и +31% скорости доставки фич. Стоит это 8 000 ₽ хостинга в месяц + 4 часа моего времени — и окупается за 4-6 недель экономией на инцидентах.
Похожая задача в вашей компании?
Расскажите, что у вас сейчас — пришлю план работ и оценку в течение рабочего дня.
Написать в Telegram или +7 903 729-62-41
Семёнов Е.С., руководитель ITfresh