1. Однієї хорошої мети недостатньо
Goal плюс current/desired behavior показують, що має стати істинним після задачі. Цього мало. 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 thresholds» — у 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 перестає бути занадто діяльним стажером, який лагодить пів будинку, і стає акуратним інженером, з яким можна працювати поруч.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ