1. Одной хорошей цели недостаточно
Goal плюс current/desired behavior показывают, что должно стать true после задачи. Этого мало. Claude видит нужный результат, но не видит разрешённую поверхность изменений — и без этой границы выбирает слишком широкий путь к вроде бы правильному итогу.
На задаче с notes это видно сразу. Можно ограничиться формой и сохранением поля, а можно полезть в DTO, сериализацию события, старый RefundService и всё, что «почти рядом». Тут и нужны Scope, Non-goals и Affected area: они переводят «что должно получиться» в «где разрешено работать».
| Блок | На какой вопрос отвечает | От чего защищает |
|---|---|---|
|
Какой результат должен появиться? | От бессмысленной работы |
|
Где разрешено менять? | От расползания diff |
|
Что сознательно не делаем? | От «заодно я ещё поправил...» |
|
Какие файлы и модули, вероятно, будут затронуты? | От слепого блуждания по проекту |
Эти три блока не заменяют цель — делают её рабочей. Без них хорошая постановка слишком добра к интерпретациям. А Claude, как вы заметили, интерпретирует старательно.
flowchart LR
A[Есть только goal] --> B[Агент сам расширяет зону помощи]
B --> C[Широкий diff]
D[Goal + Scope + Non-goals + Affected area] --> E[Узкий и понятный diff]
2. Scope: где именно разрешено работать
Scope — это не просто список файлов. Это разрешённая зона работы: какой пользовательский сценарий, какие части системы и какие сопутствующие артефакты входят в задачу.
В F-03 мало сказать «добавляем notes». Нужно назвать сценарий: оператор оформляет возврат из админки — значит, scope включает форму запроса возврата. Заметка ещё сохраняется и отображается в деталях — scope захватывает чтение и запись. Заметка уходит в событие refund.created — scope включает и событие. Первая ловушка: считать scope только кодом интерфейса, когда задача давно вышла за пределы одного экрана.
Мыслите scope в трёх плоскостях: user flow, системные точки изменения, сопутствующие проверки.
| Уровень scope | Пример для F-03 |
|---|---|
| Пользовательский поток | Оператор создаёт возврат из админки и потом открывает детали возврата |
| Точки системы | Форма запроса возврата, сохранение записи refund, отображение details, событие refund.created |
| Сопутствующие артефакты | Тесты, короткая внутренняя документация по payload события |
Рабочий фрагмент блока Scope:
## Область изменений
- форма запроса возврата в админке;
- экран деталей возврата;
- сохранение поля notes в записи refund;
- включение notes в событие refund.created;
- обновление тестов и краткой внутренней документации.
Заметьте: ни одного точного пути к файлу — и это нормально. Не знаете структуру идеально — задайте scope на уровне экранов, сервисных действий и артефактов. Не нужно быть живым индексатором репозитория, чтобы написать полезную постановку.
Плохой scope звучит либо слишком узко («добавить textarea на страницу», когда нужны ещё хранение и показ), либо слишком широко («изменить весь модуль возвратов» = для агента «гуляй, душа»). Хороший держит задачу в границах, где diff ещё читается глазами без ощущения второй работы.
3. Non-goals: что сознательно не делаем
Писать non-goals кажется почти извинением: тут не делаем, там тоже. На деле это дисциплина. Non-goals не урезают ценность задачи — они мешают агенту улучшать соседние области просто потому, что они рядом и «почти связаны».
Запомните: non-goals — это не список того, что вы забыли. Это список того, что вы осознанно не делаете в этой задаче. Если цель требует сохранять заметку в базе, объявить базу «вне scope» нельзя — это уже не защита задачи, а бегство от собственной спецификации. Non-goals работают только на соседних, необязательных изменениях.
Для F-03 разумные non-goals касаются смежных и чувствительных зон: пороги автоодобрения, логика платежей, связка тикетов поддержки. Агент легко сочтёт их «почти по теме» — скажите прямо, что сегодня туда не идём.
## Не-цели
- не менять пороги auto/manual approval;
- не трогать обработку платежей и интеграцию с PSP;
- не менять логику связывания тикета и возврата;
- не рефакторить RefundService за пределами нового поля;
- не править форматирование вне перечисленной зоны задачи.
Сравните это с фразой «ничего лишнего не делай». Для агента она бесполезна. Что считать лишним? Переименование DTO? Обновление сериализатора? Чистку старого метода? Агент ответит сам — и не факт, что так, как нужно вам.
Полезная привычка: отделяйте правила всего проекта от ограничений конкретной задачи. Общие договорённости («не коммитим временные логи», «используем существующий стек форм», «не добавляем зависимости без обсуждения») — в CLAUDE.md. «В этой задаче не меняем пороги approval» — в TASK_SPEC.md. Иначе либо захламите CLAUDE.md деталями одной задачи, либо будете в каждой постановке переписывать конституцию проекта.
4. Affected area: карта изменений
Самый практичный и недооценённый блок. Affected area отвечает на вопрос: какие файлы, модули или части системы, скорее всего, будут затронуты. Ключевое слово — «скорее всего». Это не приговор и не список в камне, а предварительная карта, чтобы агент стартовал не со всего репозитория, а с разумной рабочей зоны.
Многих этот блок пугает: не знаете точные пути — значит, писать нечего. Наоборот. Affected area особенно полезен, когда проект вы знаете неидеально. Называйте кандидатов на уровне экранов, сервисов, событий, таблиц и тестов. А если и это туманно — честно попросите агента сначала вернуть кандидатный список затронутых областей без правок.
Если проект вам примерно понятен:
## Затронутая область (предварительно)
- форма запроса возврата;
- страница деталей возврата;
- контроллер и сервис возвратов;
- событие refund.created;
- миграция таблицы refunds;
- тесты refund flow.
Если пока не уверены — формулировка для Claude:
Сначала не редактируй файлы.
Верни кандидатный список affected area для поля notes:
какие экраны, сервисы, события и тесты, вероятно, будут затронуты.
Для каждого пункта кратко укажи причину.
Методически это важно. Вы не диктуете «вот точные файлы, не спорь», но и не бросаете агента в бездну фразой «разберись сам». Вы задаёте стартовую зону поиска и просите аргументацию — это лучше выдуманных путей, которых потом не окажется.
И ещё: affected area почти никогда не сводится к продакшн-коду. Меняется поле в форме — вероятно, меняются тесты. Поле попадает в событие — возможно, придётся посмотреть контракт события. Есть документация по payload — она тоже часть зоны. Об этом забывают, а потом удивляются, почему задача вроде сделана, но ощущается незавершённой.
5. Собираем три блока в TASK_SPEC.md
По отдельности блоки полезны, но сила появляется, когда они стоят рядом в одном фрагменте. Задача перестаёт быть пожеланием и становится брифом, который отдаёшь агенту, а потом спокойно сверяешь с diff. Не «попробуй сделать фичу», а «вот границы, внутри которых работаем».
Это ещё не финальный spec. Здесь мы собираем промежуточный слой того же draft — про поверхность изменений. Ограничения способа работы добавим отдельно. Я нарочно оставлю короткие формулировки — рабочий документ, не литература:
# TASK_SPEC.md
## Цель
Добавить необязательное поле notes в запрос на возврат из админки.
## Область изменений
- форма запроса возврата;
- экран деталей возврата;
- сохранение notes в refund;
- поле notes в событии refund.created;
- обновление тестов и краткой документации.
## Не-цели
- не менять пороги approval;
- не трогать платежную интеграцию;
- не рефакторить RefundService вне задачи.
## Затронутая область
- форма возврата;
- экран деталей возврата;
- RefundController / RefundService;
- событие refund.created;
- тесты refund flow.
Видно, как блоки держат друг друга. Goal отвечает за результат. Scope — в какой зоне он достигается. Non-goals обрезает соседнее, куда захочется полезть «потому что рядом». Affected area помогает начать с конкретных кандидатов, а не с половины репозитория.
Вспомните предыдущий модуль с CLAUDE.md. Правило, повторяющееся от задачи к задаче, не таскайте в каждый TASK_SPEC.md как чемодан без ручки: «не добавлять зависимости без обсуждения» — в CLAUDE.md, «в этой задаче не меняем approval thresholds» — локальная граница работы.
Иногда по ходу задача расширяется. Думали — notes это только UI и запись в refund, а оказалось, что старые возвраты без поля должны корректно отображаться в отчётах. Правильное действие — не кодить молча, а переписать или расширить TASK_SPEC.md. Иначе классика: спецификация одна, diff другой, а объясняться придётся вам.
6. Сигналы, что задача всё ещё расползается
После заполнения блоков сделайте короткую проверку на здравый смысл. Часто расползание видно ещё до первого редактирования — по формулировкам. Это хорошая новость: поймать его в тексте дешевле, чем разбирать огромный diff и три внезапно сломанных теста.
| Сигнал в постановке | Что это обычно означает | Что лучше сделать |
|---|---|---|
| В scope звучит целый модуль | Задача пока слишком широкая | Сузить до одного пользовательского потока или одной вертикали изменений |
| Non-goals состоят из фраз вроде «ничего лишнего» | Границы неочевидны | Назвать конкретные подсистемы и решения, которые не трогаем |
| Affected area совсем пустой | Агенту придётся искать вслепую | Добавить хотя бы уровень экранов, сервисов и тестов или попросить кандидатный список без правок |
| В тексте часто встречается «заодно» | Задача начинает вбирать соседние улучшения | Вынести «заодно» в отдельную будущую задачу |
| После обсуждения список затронутого растёт в разные стороны | Спецификация устарела | Обновить TASK_SPEC.md, а не делать вид, что всё ещё в первоначальном scope |
Особенно следите за словом «заодно». В разработке оно звучит так же безобидно, как «быстро». Через «заодно» в задачу пролезают случайный рефакторинг, форматирование соседних файлов, замена сериализации, переименование моделей. Заметили, что описание уже требует «ну и тут можно чуть подчистить» — остановитесь и вынесите соседнюю идею в отдельную задачу.
Хорошая постановка ощущается приземлённо. Покажите её другому разработчику — он поймёт, где проходит граница работ. Агенту по такой постановке не нужно угадывать вашу волю по выражению лица. Когда scope, non-goals и affected area записаны ясно, Claude перестаёт быть слишком деятельным стажёром, который чинит полдома, и становится аккуратным инженером, с которым можно работать рядом.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ