1. Расследование идёт раньше правки
Очень хочется после чтения тикета и пары файлов сказать Claude: «Ну всё понятно, исправляй». А ведь это самая дорогая фраза во всей отладке. После неё вместе с багом «случайно улучшается архитектура», меняется API, ломается соседний сценарий, рождается новая эксклюзивная проблема. Поэтому расследование я держу скучным и дисциплинированным.
Intake уже сделал важную часть работы: отделил symptom, user impact, assumptions и open questions. Но пока это карта на человеческом языке. Давайте пройдём по коду и превратим assumptions в evidence — не переходя в редактирование.
Сначала понять, потом менять.
В разных версиях Claude Code точное имя команды или режима может отличаться, поэтому ориентируйтесь на текущий /help. Но суть режима планирования всегда одна: Claude читает, ищет, объясняет, собирает evidence и не редактирует файлы. Ноль правок. Ноль «ну я тут заодно уже исправил».
Вот как выглядит этот переход в виде простой схемы:
flowchart LR
A[Issue Intake Note] --> B[Режим планирования]
B --> C[Релевантные файлы]
B --> D[Точки входа и тесты]
B --> E[Риски и unknowns]
C --> F[Investigation Note]
D --> F
E --> F
Обратите внимание на важную мысль: после хорошего расследования код всё ещё не изменён. Для новичка это иногда выглядит странно: «Я поработал, а баг на месте». На самом деле это сильное состояние: карта местности есть, а вы ещё ничего не испортили.
2. Результат расследования: Investigation Note
Чтобы расследование не превратилось в бесконечный разговор с Claude о жизни, архитектуре и погоде в логах, заранее решите, что хотите на выходе. Не красивый текст, а рабочий артефакт — Investigation Note: короткий плотный отчёт, где живёт проблема и что мы про неё уже знаем на уровне кода.
Для текущего issue этого достаточно представить в виде таблицы:
| Что нужно выяснить | Пример для Commerce OS | Зачем это знать |
|---|---|---|
| Точка входа | Где обрабатывается POST /api/orders | Чтобы понимать, как запрос попадает в backend |
| Бизнес-логика | Где считается сумма заказа | Чтобы найти минимальную точку изменения |
| Существующие тесты | Есть ли тест на пустую корзину | Чтобы не писать всё с нуля и не дублировать покрытие |
| Обработка ошибок | Есть ли уже общий маппинг 400 | Чтобы не изобретать новый механизм там, где старый уже есть |
| Риски и unknowns | Что ожидает frontend, где ещё используется метод | Чтобы не вылезти за scope и не сломать соседние сценарии |
Хороший запрос к Claude в режиме планирования может выглядеть так:
Перейди в режим планирования. Не редактируй файлы.
Исследуй, где реализована ошибка из issue #482.
Верни:
1. релевантные файлы,
2. ключевые методы и точки входа,
3. существующие тесты,
4. вероятные точки изменения,
5. риски,
6. assumptions и evidence под каждый вывод.
Заметьте: здесь нет просьбы «предложи красивый рефакторинг» и «сразу исправь». Сначала — карта проблемы. И ещё одна тонкость: это не широкое знакомство с codebase, мы сужаемся до одного issue.
3. Не начинайте с пустого экрана
Чтобы не говорить абстрактно, возьму учебный пример из Commerce OS. Intake готов, фрагмент артефакта:
## Проблема
POST /api/orders возвращает 500 при пустом items[].
## Влияние на пользователя
Пользователь получает общую ошибку вместо понятной валидации.
## Известные доказательства
- stack trace из тикета
- воспроизведение: POST /api/orders с пустым items[]
## Открытые вопросы
- нужен ли отдельный код ошибки EMPTY_CART?
- должен ли frontend показывать специальный текст?
## Вне области
- редизайн корзины
- изменения checkout UX
Теперь к делу. Самая полезная привычка здесь — не начинать расследование с пустого экрана. У вас уже есть CODEBASE_INVENTORY.md из модуля про анализ проекта и API_MAP.md из модуля про карту API — стартовые ориентиры. Если в API_MAP.md есть запись про /api/orders, не делайте вид, будто впервые видите этот endpoint. Используйте собранную карту, а не стройте заново героическим усилием.
Если issue приходит через issue-tracker из Workflow Kit — ещё лучше: попросите Claude подтянуть текст тикета, релевантные комментарии и labels, не копируя руками. Например, комментарий frontend-разработчика про ожидаемый код ошибки нередко полезнее половины обсуждения. Но и здесь нужна дисциплина: берём то, что помогает расследованию, а не весь корпоративный роман в четырёх томах.
4. От тикета к файлам: точки входа и связи
А теперь спускаемся с небес на землю — к самой прикладной части. Расследование почти всегда идёт по одной и той же траектории: точка входа → бизнес-логика → тесты → обработка ошибок → change points. Если вы только начинаете программировать, считайте это надёжным маршрутом. Скучно, но работает лучше, чем «я интуитивно чувствую, что баг живёт в сервисах».
Если rg звучит как название боевого дроида из научной фантастики — не пугайтесь. Это просто быстрый поиск по проекту. В терминале можно начать так:
rg '@PostMapping\("/api/orders"' src test # ищем контроллер маршрута
rg 'calculateTotal\(' src test # ищем расчёт суммы и его тесты
rg 'IllegalArgumentException|ControllerAdvice' src test # ищем общую обработку ошибок
Даже если вы не любите терминал, тот же маршрут проходится через поиск в IDE. Важно не то, каким именно инструментом вы ищете, а в каком порядке вы это делаете. Сначала вход, потом логика, потом проверки.
Предположим, расследование выводит нас на контроллер создания заказа:
@PostMapping("/api/orders")
public OrderResponse create(@RequestBody CreateOrderRequest request) {
BigDecimal total = orderService.calculateTotal(request.items()); // тут возможна ошибка
return orderFacade.createOrder(request, total);
}
Это уже evidence, а не догадка. Мы видим, что запрос действительно входит через этот метод, и дальше уходит в orderService.calculateTotal(...). Следующая остановка — сервис:
public BigDecimal calculateTotal(List<OrderItem> items) {
Currency currency = items.get(0).currency(); // пустой список ломает расчёт
BigDecimal total = BigDecimal.ZERO;
for (OrderItem item : items) {
total = total.add(item.priceIn(currency));
}
return total;
}
Теперь у нас появляется сильная гипотеза: падение на пустом списке происходит именно здесь. Но пока это ещё не финальная истина, а хорошо обоснованная гипотеза. Почему? Потому что нам ещё нужно проверить, нет ли рядом общей валидации, уже существующего обработчика ошибок и не используется ли этот метод где-то ещё, кроме создания заказа.
И вот здесь расследование становится инженерным, а не «магическим». Мы не говорим: «Ага, понял, вот root cause». Мы говорим: «Есть кодовый фрагмент, который подтверждает вероятную точку падения. Теперь проверим соседние условия». Это взрослая разница.
5. Отличаем evidence от гипотезы
Одна из самых полезных привычек, которую вы можете унести из этой лекции, звучит просто: каждый вывод должен иметь статус. Либо это evidence, либо hypothesis, либо assumption, либо unknown. Если всё смешать в одну кучу, Investigation Note превратится в уверенно звучащий текст, который очень плохо выдерживает встречу с реальным diff.
Вот простая таблица для нашего случая:
| Формулировка | Статус | Почему |
|---|---|---|
| POST /api/orders обрабатывается в OrderController#create | Evidence | Мы видим аннотацию маршрута и метод |
| calculateTotal() падает на пустом списке | Evidence | В коде есть items.get(0) без проверки |
| Это единственная причина бага | Hypothesis | Надо ещё проверить валидацию и обработку исключений |
| Frontend ждёт код EMPTY_CART | Assumption | Это может идти из комментария, но не из кода backend |
| calculateTotal() больше нигде не используется | Unknown, пока не проверили | Нужен поиск usages |
Очень частая ошибка новичка выглядит так: увидели подозрительную строку — объявили дело раскрытым. Но хороший investigation живёт чуть иначе. Он постоянно задаёт уточняющие вопросы. Есть ли уже @ControllerAdvice, который умеет превращать IllegalArgumentException в 400? Есть ли тесты на похожие сценарии валидации? Не используется ли calculateTotal() в пакетной обработке заказов, где пустой список вообще не должен доходить до сервиса?
Иногда Claude уже на этом этапе полезно попросить не «объяснить архитектуру», а ответить очень приземлённо: что является фактом, а что предположением. Такой запрос звучит почти смешно, но работает прекрасно:
Для каждого вывода в расследовании пометь статус:
evidence, hypothesis, assumption или unknown.
Не превращай hypothesis в факт.
Здесь мы буквально учим AI не поддаваться его любимой слабости: уверенно звучать там, где надо честно сказать «пока не знаю». И, честно говоря, людям это тоже иногда полезно.
6. Оформляем Investigation Note для других
Хорошее расследование ценно не только тем, что вы сами что-то поняли. Оно должно оставлять после себя артефакт, который сможет за две минуты прочитать другой инженер, ревьюер или вы сами через три дня. И вот тут длинная история чата почти всегда проигрывает короткому Investigation Note.
Пример для нашего issue может выглядеть так:
# Заметка расследования
## Релевантные файлы
- orders/api/OrderController.java
- orders/service/OrderService.java
- orders/api/GlobalExceptionHandler.java
- orders/test/OrderControllerWebTest.java
## Вероятные точки изменения
- валидация empty items до calculateTotal()
- возврат 400 вместо 500
- возможно: reuse существующего error mapping
## Доказательства
- route найден в OrderController#create
- stack trace указывает на OrderService.calculateTotal:42
- в calculateTotal есть items.get(0) без проверки
- теста на empty cart в OrderControllerWebTest не найдено
## Неизвестное
- есть ли другие usages calculateTotal()
- какой error code ожидает frontend
Обратите внимание на стиль этого документа. Он короткий. В нём нет романа про архитектурное величие системы. Каждая секция отвечает на конкретный вопрос. Такой артефакт гораздо полезнее, чем 40 сообщений в сессии, где удачные мысли перемешаны с неудачными гипотезами и вопросами вроде «а может, всё-таки переписать сервис?». Нет, не надо. Мы сегодня не переписываем сервис. Мы сегодня аккуратно понимаем, где живёт проблема.
Если вам хочется добавить в Investigation Note всё подряд, задайте себе простой вопрос: поможет ли это другому человеку принять следующий инженерный шаг? Если нет, убирайте. Investigation Note — это не исповедь, а рабочая записка.
7. Reviewer-agent как вторая пара глаз
На этом этапе очень приятно переиспользовать то, что вы уже собрали в Workflow Kit. Reviewer-agent нужен не только для кода и PR. Он отлично работает как вторая пара глаз для расследования. Причём это как раз тот случай, когда subagent особенно уместен: основная сессия занята исследованием, а reviewer получает уже готовый Investigation Note и проверяет качество выводов.
Запрос здесь может быть таким:
Проверь Investigation Note как reviewer.
Для каждого вывода ответь, есть ли под ним evidence.
Если evidence слабое или отсутствует, пометь это как unknown.
Не предлагай реализацию и не редактируй код.
Чем хорош такой шаг? Во-первых, он не засоряет основную сессию тонной промежуточных комментариев. Во-вторых, fresh-context reviewer часто замечает то, что writer-сессия уже перестала видеть. Это классический эффект: когда вы сами долго расследуете issue, у вас в голове уже сложилась «любимая версия». Reviewer-agent помогает проверить, не начали ли вы случайно выдавать эту любимую версию за факт.
Важно только не перекладывать на него ответственность. Reviewer-agent не выносит приговор. Он подсвечивает слабые места. Решение всё равно принимаете вы: достаточно ли evidence, можно ли переходить к плану, где нужно доисследовать, а где неизвестность допустима.
8. Действия при оставшихся unknowns
Вот здесь многие впервые выдыхают и понимают, что расследование не обязано давать стопроцентное знание о мире. Наличие unknowns — не провал. Провал — делать вид, что их нет. В живых проектах какие-то вопросы почти всегда остаются. Вопрос только в том, какие именно.
Если unknown касается косметической детали, например текста сообщения для frontend, его можно честно зафиксировать как assumption и принять отдельно позже. Если unknown касается публичного API, shared-метода, схемы данных или скрытого использования сервиса в других потоках, это уже стоп-линия. Здесь не надо «надеяться, что всё будет нормально». Нужно либо доисследовать, либо поднять вопрос человеку, который владеет этой областью.
Полезно различать два типа неизвестности. Первая — рабочая, допустимая. Например: «frontend ожидает один из двух вариантов error code, уточнить при согласовании». Вторая — блокирующая. Например: «непонятно, используется ли calculateTotal() в nightly job, где поведение на пустом списке принципиально иное». Во втором случае двигаться дальше рано. И это нормально.
Хорошее расследование заканчивается не фразой «теперь всё абсолютно ясно», а состоянием, в котором у вас есть читаемая карта: релевантные файлы, точки входа, evidence, риски и честно помеченные unknowns. Код при этом всё ещё не изменён ни на строчку. И это отличный результат. Потому что теперь вы входите в следующий инженерный шаг не с фонариком в тумане, а с нормальной картой, на которой уже отмечено, где дорога, где болото, а где лучше не срезать путь, даже если Claude очень уверенно предлагает «быстро и красиво».
9. Облачный планировщик как ускоритель
Всё, что мы разбирали выше, — это классический локальный plan mode: вы сами ведёте сессию, читаете evidence, складываете Investigation Note. Современные версии Claude Code предлагают для того же сценария ещё один режим — облачный планировщик с расширенным бюджетом контекста и встроенной проверкой плана самим собой. Запускается одной командой (условно /ultraplan, точное имя и доступность могут меняться от версии к версии). Ментальная модель здесь очень простая: это тот же plan mode, который мы только что разобрали, но вынесенный в облачное окружение, где у агента больше контекста и есть встроенный разбор собственного плана перед тем, как отдать его вам.
На выходе вы получаете готовый пакет: Investigation Note, Implementation Plan, список рисков и стратегию проверки в одном документе, уже прошедший внутренний разбор плана самим планировщиком.
Когда облачный планировщик уместен
Если задача затрагивает несколько модулей Commerce OS, и evidence приходится собирать по большому коду, который локально просто не помещается в контекст сессии. Вы только разбираетесь в проекте, и обычной сессии не хватает контекста, чтобы строить выводы на evidence, а не на догадках. Нужен план для изменения с высоким риском — аутентификация, платежи, миграции, — и встроенное второе мнение оправдывает дополнительную задержку.
Расследование локально займёт более получаса, а облачный агент при этом работает параллельно, пока вы готовите baseline или тесты. Наконец, миграционный discovery — каноничный случай: там пакет доказательств обычно большой, changelog, матрица совместимости, граф зависимостей, и облачный контекст здесь буквально для этого и нужен.
Отдельно отмечу, что на момент написания этого курса облачный планировщик не давал особого выигрыша в планировании. Скорее это дополнительный способ заработать денег для Anthropic, если вы уже пользуетесь подпиской Claude Code. Надо же вам ещё что-то продать за деньги :)
Когда облачный планировщик не уместен
Задача маленькая и понятная — накладные расходы на облачный запуск больше, чем выигрыш. Репозиторий или данные нельзя выгружать в облачное окружение — это чувствительные данные или регулируемая среда, и тогда вопрос вообще не в качестве плана, а в политике безопасности, которую мы подробно разбираем в следующих уровнях курса. Вы не сможете валидировать возвращённый план — это вообще базовое правило: облачный планировщик не отменяет границу одобрения, а план без понимания опаснее, чем отсутствие плана. И, наконец, срочный hotfix — выигрыш в качестве плана не оправдывает задержку.
Разрешения для облачного запуска — отдельная история, к которой мы ещё вернёмся в курсе. У облачного агента отдельная модель разрешений: свой биллинг, свой журнал аудита, свой набор разрешённых файлов и путей. Это должно быть явно зафиксировано в командной политике: какие задачи допустимо отдавать в облачное планирование, какие — только локально.
Ключевая формула при этом не меняется. Облачный вариант не отменяет границу одобрения. Планировщик предлагает — человек утверждает.
Результат облачного запуска идёт ровно в тот же поток работы, что и расследование, собранное локально: вы читаете план, утверждаете или корректируете, передаёте в Implementation Plan (следующая лекция), а оттуда — в управляемую реализацию, к которой мы перейдём в следующем уровне. Облачный планировщик — это способ получить план быстрее и с большим контекстом, а не способ обойти проверку.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ