1. Смотрим не на объяснение, а на diff
К этому моменту изменение уже собрано: root cause зафиксирован, regression evidence под рукой, diff разложен на commit'ы, а PR_DESCRIPTION.md объясняет суть. Но это ещё не значит, что PR можно молча отправлять дальше. Тесты зелёные, Claude бодро пишет «готово, всё работает» — и именно здесь тянет расслабиться. Инженерная дисциплина начинается там, где хочется закрыть ноутбук.
У diff есть очень полезное свойство: он не рассказывает историю, а показывает факт изменения. Diff — это кассовый чек вашей правки: потом не спорят, что именно вы «купили» у кода и почему в корзине оказались ещё три лишних файла.
Раньше мы читали маленький diff после каждого шага, чтобы удерживать implementation loop под контролем. Здесь масштаб другой: должны сходиться файлы, commit'ы, walkthrough и evidence — review всего изменения, а не проверка микрошага.
Здесь полезно на секунду напомнить разницу между verification и review: первое отвечает на «чем мы доказали корректность», второе — «кто посмотрел и принял локальное решение». Нас интересует review-слой.
| Что сравниваем | На какой вопрос отвечает |
|---|---|
| Verification | Что мы запускали, чем проверяли, какие тесты и команды дали evidence |
| Layer 1 review | Кто посмотрел на diff, что заметил и почему решил, что PR готов или не готов |
Чтобы не говорить слишком абстрактно, возьмём сквозной пример из Commerce OS. Баг: пустая корзина приводила к 500 при checkout. Approved plan выглядел так:
## Утверждённый план
1. Добавить guard для пустой корзины в `OrderController`.
2. Добавить regression test в `OrderControllerTest`.
3. Не менять другие endpoints и не трогать логику `/orders/preview`.
А вот фрагмент реального diff:
public OrderResponse checkout(@RequestBody CheckoutRequest request) {
+ if (request.items() == null || request.items().isEmpty()) {
+ throw new InvalidRequestException("Корзина пуста");
+ }
+ return checkoutService.checkout(request.items());
}
С этого момента ваша задача — не радоваться тому, что «guard же добавили», а задать спокойные инженерные вопросы. Совпадает ли это с approved plan? Не уехал ли diff куда-то ещё? Изменили ли поведение шире, чем собирались? Есть ли тест? Не сломали ли соседний путь? Вот точка входа в локальное review.
2. Состав Layer 1 review
Само слово review иногда звучит пугающе, как будто сейчас придёт сердитый сеньор, увидит лишнюю строчку и отправит переписывать карьеру. На деле Layer 1 review — локальная последовательность шагов, которая не даёт выпустить сырой PR и делает его чистым и объяснимым уже на вашей стороне. Удобно видеть его как маленький конвейер:
flowchart TD
A[Approved plan + diff] --> B[Self-review]
B --> C[Claude-assisted review]
C --> D[Fresh-context review]
D --> E[Review notes]
E --> F[Human decision]
Если в проекте уже одобрен какой-то review-плагин, его можно встроить между fresh-context review и итоговым решением. Но важно не путать инструмент с судьёй: плагин или Claude помогают заметить проблему, а не принимают решение за вас.
Ниже — вся логика в одной таблице.
| Шаг | Кто смотрит | Зачем нужен | Что получается на выходе |
|---|---|---|---|
| Self-review | Вы как автор | Проверить, совпадает ли diff с планом и смыслом задачи | Первичная локальная оценка diff |
| Claude-assisted review | Claude в writer-сессии или отдельном запросе | Быстро подсветить scope creep, missing tests, edge cases | Список находок с уровнем важности |
| Fresh-context review | Другая сессия или reviewer-subagent | Снять замыленность автора и confirmation bias | Второй взгляд без авторской истории |
| Plugin-assisted review | Опционально, если plugin уже одобрен | Добавить ещё один автоматизированный прожектор | Дополнительные замечания |
| Облачное ревью | Опциональный ускоритель: многоагентный разбор сложного diff в облаке | Получить расширенный контекст и сразу несколько специализированных взглядов | Единый отчёт со сведёнными находками |
| Human decision | Вы или живой ревьюер | Принять решение: готово, исправляем, делим PR | Осознанный go / no-go |
Самое важное здесь — порядок: сначала вы сами читаете свой diff, потом подключаете Claude, потом даёте diff «свежей голове», и только затем формируете REVIEW_NOTES.md. Пропустите self-review, сразу спросив модель «ну как там?» — и вы назначаете Claude своим заместителем по ответственности. Плохая кадровая политика.
3. Self-review: сначала вы, потом уже Claude
Self-review кажется скучным ровно до первого раза, когда вы находите в своём PR лишний файл, случайный rename или правку «заодно», которую вчера даже не заметили. Он снимает самые дешёвые ошибки — те, что потом обидно ловить на чужом review.
Если вы пока чувствуете себя неуверенно, не пытайтесь читать diff как Матрицу. Начните с простой схемы: сначала масштаб, потом затронутые файлы, потом поведенческий смысл, потом тесты.
git diff --stat # быстро смотрим масштаб изменений
git diff src/orders/OrderController.java # читаем смысл production-правки
git diff src/orders/OrderControllerTest.java # отдельно проверяем regression test
git status # нет ли случайно лишних файлов
Теперь полезно сверять diff с approved plan почти как по чек-листу, но без бюрократического фанатизма.
| Что сверяем | Какой вопрос задаём себе |
|---|---|
| Список файлов | Все ли эти файлы действительно были в плане? |
| Поведение | Исправляю ли я именно тот сценарий, ради которого открыл задачу? |
| Тесты | Есть ли явный regression test или хотя бы обновлённая проверка? |
| Scope | Не затронул ли я соседние endpoint'ы, конфиги или рефакторинг «за компанию»? |
| Читаемость | Могу ли я объяснить этот diff за минуту без фразы «ну тут Claude сам решил»? |
Допустим, кроме guard в OrderController вы внезапно видите ещё и изменение в OrderPreviewController. Вот здесь self-review и должен вас остановить: Claude «хотел помочь» — сделать поведение единообразным, но approved plan прямо сказал /orders/preview не трогаем. Это не улучшение, а scope creep.
Полезно также смотреть не только на добавленные и удалённые строки, но и на изменившийся смысл. Например, вот маленький тест:
import org.junit.jupiter.api.Test;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@Test
void rejectsEmptyCart() throws Exception {
mockMvc.perform(post("/api/orders")
.contentType("application/json")
.content("{\"items\":[]}"))
.andExpect(status().isBadRequest());
}
Сам по себе он выглядит хорошо. Но self-review подталкивает к ещё одному вопросу: тест закрывает старую болевую точку из root cause — или мы просто повесили зелёную лампочку на похожий сценарий? Если баг проявлялся на HTTP-уровне, а тест уходит только во внутренний exception, часть проблемы всё ещё рядом. Финальная самопроверка: если бы этот PR открыл не я, а коллега, смог бы я по diff быстро понять, что произошло и зачем? Ответ «примерно, но пришлось бы вспоминать контекст чата» означает — PR ещё сыроват.
4. Claude-assisted review: правильный фокус
После self-review очень удобно подключить Claude как второго читателя diff. Но здесь есть тонкая ловушка: спросите просто «проверь PR» — и модель начнёт помогать слишком широко. А «слишком широко» в review почти всегда значит «слишком расплывчато». Давайте Claude не свободу, а фокус:
Проверь текущий diff против approved plan.
Смотри только на:
- расползание scope,
- отсутствующие тесты,
- крайние случаи,
- обратную совместимость,
- чувствительные изменения в валидации,
- неясные места в коде.
Сгруппируй находки по важности: blocker / major / minor.
Укажи file:line, если это возможно.
Файлы не редактируй.
Здесь важны сразу три вещи: связь с approved plan, список зон внимания, запрет на редактирование. Вам сейчас нужен reviewer, а не «ревьюер, который на всякий случай уже всё сам поправил». Claude в этом режиме быстро сканирует diff и приносит список гипотез, которые вы дальше либо подтверждаете, либо отклоняете.
| Уровень | Что означает | Как обычно реагируем |
|---|---|---|
| Blocker | PR нельзя считать готовым | Исправляем до любого движения дальше |
| Major | Существенный риск или заметный пропуск | Обычно правим в этом же PR |
| Minor | Улучшение читаемости, имени, формулировки | Исправляем по ситуации |
Представим, что Claude вернул major («/orders/preview по-прежнему позволяет пустую корзину») и minor («имя теста rejectsEmptyCart можно точнее»). Но это ещё не приговор: вы читаете, соотносите со scope и решаете.
Очень полезная привычка — фиксировать не только принятые, но и отклонённые замечания. Потому что Claude иногда звучит так уверенно, будто уже сам себе одобрил PR и пошёл за кофе. А часть замечаний может не иметь отношения к текущему scope.
## Claude-assisted ревью
- Major: endpoint `/orders/preview` не покрыт новой валидацией — принято, открываем follow-up issue
- Minor: тест `rejectsEmptyCart` можно переименовать в `returnsBadRequestForEmptyCart` — принято
- Minor: добавить логирование в controller — отклонено, вне scope текущего PR
Так review перестаёт быть размытым разговором «что-то где-то не понравилось» и становится набором решений. А решения любят быть записанными.
5. Fresh-context review: свежий взгляд
После пары часов работы над одной задачей происходит очень человеческая вещь: вы видите в diff не то, что написано, а то, что хотели написать. Именно поэтому fresh-context review так полезен — это не недоверие к себе, а нормальная инженерная прививка от замыленного взгляда.
Самый простой вариант — открыть новую Claude-сессию и дать ей только нужные артефакты: approved plan, PR_DESCRIPTION.md, diff и test plan. Ещё удобнее reviewer-subagent из Workflow Kit — заново мы его не настраиваем, просто используем как свежую пару глаз.
Ты — reviewer свежим контекстом.
У тебя нет истории writer-сессии.
Проверь текущий diff против approved plan и PR walkthrough.
Сфокусируйся на:
- несоответствии plan ↔ diff,
- пропущенных крайних случаях,
- неочевидных изменениях поведения,
- тестовых пробелах.
Верни findings с важностью и коротким обоснованием.
Файлы не редактируй.
Почему fresh-context review работает лучше, чем «тот же Claude, но ещё раз»? Потому что writer-сессия уже накопила историю решений, гипотез, отвергнутых путей и эмоциональное ощущение «ну я же знаю, что тут происходит». Новая сессия этого багажа не имеет — она смотрит на PR так же, как потом посмотрит живой ревьюер.
В нашем примере с Commerce OS свежий reviewer замечает то, что writer уже перестал видеть: walkthrough обещает HTTP 400 для POST /api/orders, а в проверках рядом указан только targeted test. Ручную HTTP-проверку правда прогоняли — или её надо добавить в evidence либо убрать из walkthrough? Это и есть золото fresh-context review.
Если diff заметно многослойный — задевает безопасность, тесты и производительность одновременно, — можно сделать ещё один шаг и запустить несколько специализированных reviewer-агентов параллельно: один на security-угол, другой на тесты, третий на архитектуру. Но это уже опция, а не обязанность: для большей части PR хватит одного свежего reviewer'а.
И ещё одна важная мысль: свежий reviewer не должен превращаться в «третейского судью, который всегда прав». Он приносит новый сигнал. Решение по сигналу по-прежнему за человеком.
6. REVIEW_NOTES.md и человеческое решение
Когда self-review, Claude-assisted review и fresh-context review закончены, важно не оставить результат распылённым по чату, памяти и вкладкам терминала. В этот момент появляется второй главный артефакт лекции — REVIEW_NOTES.md. Если PR_DESCRIPTION.md рассказывает ревьюеру что и зачем вы поменяли, то REVIEW_NOTES.md фиксирует, как именно вы локально проверяли PR и к чему пришли.
# REVIEW_NOTES.md
## Self-review
- diff совпадает с шагами approved plan
- изменены только `OrderController` и `OrderControllerTest`
- unrelated files отсутствуют
## Claude-assisted ревью
- Minor: переименовать тест для большей ясности — принято
- Major: проверить согласованность с `/orders/preview` — follow-up issue создан
## Ревью на свежем контексте
- подтверждено: scope не расползся
- найдено: manual check в PR walkthrough стоит уточнить — принято
## Финальное решение
PR готов к отправке на внешний review.
Открытые follow-up задачи не блокируют текущий bugfix.
Обратите внимание на последнюю секцию. Она называется не «одобрено Claude», не «всё отлично» и не «ну вроде можно». Она называется Final decision. Потому что именно здесь заканчивается локальная автоматизация и начинается человеческая ответственность.
По сути, разумных решений обычно четыре. PR готов. Либо требует ещё одного небольшого исправления. Либо его лучше разбить на два — diff вырос или затесалась лишняя идея. Либо review возвращает вас в debugging: root cause описан слабо. Все четыре нормальны. Ненормален только пятый: «ничего не понял, но ладно, отправлю так».
Человеческое решение и есть точка, в которой локальный Layer 1 review заканчивается. У вас чистый diff, понятный PR_DESCRIPTION.md, зафиксированный REVIEW_NOTES.md, список принятых и отклонённых замечаний. Три взгляда — свой, Claude и свежий контекст — уже отсеяли лишние файлы, scope creep и дыры в тестах, но последнее слово осталось не за ними. Self-review, Claude и fresh-context только подсвечивают проблемы; строку Final decision пишете вы. И именно эта подпись, а не зелёные галочки инструментов, превращает «то, что Claude где-то нагенерировал» в изменение, за которое отвечает человек.
7. Облачное ревью как ускоритель
Облачное ревью — это естественное продолжение ревью со свежим взглядом для случаев, когда локального reviewer-subagent уже не хватает. Запускается одной командой (условно /ultrareview или похожая облачная команда; точное имя и доступность могут меняться от версии к версии). Ментальная модель та же: это то же самое ревью со свежим взглядом, что и в шаге fresh-context, только вынесенное в облачное окружение.
Чем это отличается от многоагентного ревью, которое вы и так можете поднять локально из Workflow Kit? Расширенным контекстом. На один и тот же diff параллельно смотрят несколько специализированных агентов — по безопасности, производительности, тестам и архитектуре, — и всё сводится в размеченный diff с находками, ссылками на файлы и уровнем серьёзности. Отчёт ложится в тот же REVIEW_NOTES.md, что и обычные находки.
Когда облачное ревью уместно
Есть несколько ситуаций, где облачное ревью оправдывает себя. Diff большой или трогает несколько слоёв сразу — аутентификация, база, API в одном PR. PR в чувствительной зоне — платежи, секреты, данные клиентов: нужен отдельный взгляд на безопасность и риск. Ревью нужно запустить параллельно с другой работой — облачный агент идёт в фоне. Diff несёт регрессионный риск, который трудно поймать одним ревьюером, — многофайловый рефакторинг или совместимость при миграции, к этим темам мы ещё вернёмся в следующих уровнях курса. Наконец, PR относится к новому или сложному модулю, где у локального ревьюера нет полного контекста архитектуры.
Каждый запуск ultrareview оплачивается отдельно и стоит от $5 до $25 в зависимости от размера. Знать, что этот инструмент существует, важно; запускать его на каждый PR — нет.
Когда облачное ревью не уместно
И столько же ситуаций, где облачное ревью только мешает. Маленький PR с очевидным diff — расходы и задержка больше выигрыша. Репозиторий или данные нельзя выгружать в облако — чувствительные данные или регулируемая среда: вопрос политики, а не качества ревью. Вы не сможете осмысленно прочитать находки задним числом — облачное ревью не отменяет обязанности читать diff и принимать решения. Срочный hotfix — на разбор отчёта нет времени.
Отдельная история — разрешения для облачного ревью, к которой мы ещё вернёмся в курсе. У облачного ревьюера своя модель разрешений: отдельный биллинг, отдельный журнал аудита, отдельный набор разрешённых файлов и путей. Командная политика должна явно описывать, какие PR допустимо туда отправлять; чаще всего это доступ только на чтение к diff и связанным файлам, без записи.
И напоследок — главное правило, которое не меняется ни на одном уровне ревью: AI-ревью любого уровня — от self-review до облачного — помогает найти проблемы, но не заменяет чтение diff и ответственность разработчика.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ