1. Довга задача ламається не в коді, а в процесі
Довга задача ламається не через те, що модель «погано кодить», а тоді, коли процес втрачає форму: контекст розростається, гіпотези перемішуються, ви обговорюєте три проблеми одночасно, diff не читається.
Візьмімо AI Commerce Growth OS. Треба винести refund-логіку з RefundController у RefundService: не зламати API, не чіпати платіжного провайдера, зберегти поведінку. Дайте Claude запит «відрефактори refund-flow і зроби код нормальним» — і корисність без меж розповзеться: через пів години обговорюєте DTO, exception handler, логи й pagination у сусідньому модулі. Не задача, а клубок задач.
| Якщо працювати «одним заходом» | Якщо працювати як інженерний процес |
|---|---|
| Один великий запит | |
| Безіменна сесія | Іменована сесія під конкретну задачу |
| Правки «раз уже ми тут» | Жорсткий scope і заборона на unrelated work |
| Один коміт наприкінці | Малі коміти на межах етапів |
| Зупинка через втому | Stop points за планом |
| Пам’ять тільки в діалозі | Summary і decision log |
Довга AI-assisted задача — це не великий prompt, а маленький інженерний процес. Не спроєктуєте його — задача попливе раніше, ніж зламається код.
2. Каркас довгої задачі: spec і milestones
Щоб задача не розповзалася, їй потрібен каркас на три питання: що робимо, чого не робимо, де зупиняємося перевіряти стан. Перетворюйте task spec одразу на скелет процесу — мета, обмеження, поділ на етапи:
# TASK_SPEC: refund-flow refactor
## Мета
Винести refund decision logic з RefundController у RefundService.
## Область змін
Лише refund-flow.
## Не-цілі
Не змінювати payment provider integration.
Не змінювати публічний API.
Не змінювати схему БД.
## Обмеження
Зберегти поточну поведінку та зелені тести.
## Майлстоуни
M1 — зафіксувати поточну поведінку тестами
M2 — винести логіку в RefundService
M3 — зробити контролер тонким і ще раз перевірити інтеграційні тести
## Точки зупинки
Після кожного milestone: summary + checks + commit
Задача отримала форму: Claude не блукає «ще покращу пару місць», а йде коридором.
flowchart TD
A[TASK_SPEC] --> B[Named session]
B --> C[Milestone 1]
C --> D[Summary + checks + small commit]
D --> E[Milestone 2]
E --> F[Summary + checks + small commit]
F --> G[Milestone 3]
G --> H[Stop point / finish]
Milestones роблять задачу переносною та перевірюваною. Без них незрозуміло, де вона, і будь-яка пауза стає болем.
3. Іменована сесія: у задачі має бути ім’я
Задача живе довше за десять хвилин — безіменна сесія працює проти вас. Скоро у вас «та довга про refunds», «ще одна схожа, але там тести» і «якась, де Claude пропонував util-клас». Пам’ять підводить уже не модель, а вас.
Дайте задачі ім’я, що збігається з workstream, branch і змістом task spec:
| Що іменуємо | Приклад |
|---|---|
| Задача | |
| Branch | |
| Session | |
Тоді у вас не три сутності, а один маршрут: задача, гілка, сесія, зміни. До першої перерви — дрібниця, після першого обіду — порятунок.
Відновлення:
# точна назва команди і прапорця залежить від версії Claude Code
claude --resume refund-refactor
Важлива не команда, а звичка: сесія прив’язана до задачі, а не висить як «ще один чат». Назва на кшталт new chat, session-12 або test2-final-final — сигнал, що процес іде в хаос.
4. Milestone summary і decision log
Історії діалогу мало: пам’ять виносять назовні короткими висновками. Milestone summary — «де ми зараз», decision log — «які рішення ухвалено, щоб через пів години не сперечатися знову».
Мінімальний summary після етапу:
## Підсумок етапу: M1
Готово:
- додані тести на поточну refund-поведінку
- зафіксовані кейси partial refund і approval > $100
Відкриті питання:
- кейс refund > $1000 поки не покритий
Ризики:
- integration path з payment provider ще не перевірено
Далі:
- винести decision logic у RefundService
Decision log:
## Лог рішень
- threshold $100 залишаємо у властивості конфігурації
- payment provider integration у цьому refactor не чіпаємо
- не переносимо exception mapping у цю саму задачу
Жити в одному «правильному» файлі ці нотатки не зобов’язані: поруч із задачею, у нотатці до гілки, у markdown. З них складається handoff для fresh session або reviewer.
Без журналу сесія живе в режимі «здається, ми це вже обговорювали»: Claude знову пропонує відхилений варіант, а ви згадуєте про це через кілька повідомлень. Добрий summary — це знімок стану, а не звіт для начальства.
5. Stop points: зупинятися за планом
Задачі псуються через невдалу зупинку. Найчастіший stop point: «Гаразд, втомився, завтра продовжу». Втома — поганий критерій: задача кинута в випадковій точці.
Добрий stop point — кінець осмисленого шматка: додали characterization tests; винесли логіку в сервіс і прогнали перевірки; зробили контролер тонким і подивилися diff. Це місце, де задачу можна безпечно передати навіть собі майбутньому: зрозуміло, що зроблено, чого немає, які перевірки запускалися, який наступний крок.
Малий commit на межі етапу зменшує ціну продовження:
git commit -m "test(refund): characterize approval rules"
git commit -m "refactor(refund): extract RefundService"
Summary пояснює зміст етапу, commit фіксує стан файлів. Лише commit — не видно рішень за ним; лише текст — нічого продовжувати.
І ще: stop point не дає тягнути стороннє. «А зараз би ще заодно підправити формат логів» — запитайте: це частина milestone чи інша історія? У дев’яти випадках із десяти — інша.
6. Context rot: коли сесія пам’ятає зайве
Забруднення контексту ви вже бачили на коротких задачах. На довгій воно підступніше: контекст не просто переповнюється — він старіє. Це context rot: сесія тягне старі гіпотези та відхилені ідеї як живі.
Ви вирішили не виносити refund-логіку в RefundUtils — це розмиє межі відповідальності. Через сорок хвилин контекст розрісся, і Claude знову: «Можливо, варто винести спільну логіку в utility class». Не навмисно — стара гіпотеза сидить поруч із новими даними.
Мінісценка:
Ви: utility class не підходить, залишаємо сервісний шар
Claude: зрозумів, ідемо через RefundService
...
через 30 хвилин
Claude: щоб зменшити дублювання, можна винести логіку в RefundUtils
Проблема не у відповіді — сесія почала гнити. Інші ознаки: ходить колами по відхилених варіантах, змішує підходи, посилається на застарілі assumptions, лізе у файли поза scope.
Не дотискайте. Зупиніться, зберіть summary, зафіксуйте рішення, продовжуйте з чистого стану. Розпізнати context rot — не слабкість, а дисципліна.
7. Два режими задачі: покроковий і goal-driven
Каркас є — як вести задачу? Два режими: покроковий і goal-driven (робота до формально перевірюваної умови завершення). Питання — який безпечніший.
Порівняймо:
| Покроковий режим | Goal-driven режим |
|---|---|
| Після кожного кроку ви підтверджуєте, що робити далі | Claude іде кілька ходів поспіль до досягнення умови завершення |
| Краще для ризикованих змін | Краще для добре обмежених задач |
| Підходить, коли потрібно багато людських рішень | Підходить, коли є детерміновані перевірки |
| Повільніше, але прозоріше | Швидше, але потребує хорошого verification harness |
Покроковий — класика для чутливих задач: крок, diff, перевірки, рішення, далі. Особливо там, де зачеплені гроші, зовнішні контракти або форма рішення ще не ясна.
Goal-driven добрий лише тоді, коли кінець перевіряє машина — є machine-checkable termination condition без ваших суб’єктивних оцінок.
Погані умови:
| Погане формулювання | Чому воно погане |
|---|---|
| «Зроби акуратно» | Машина не знає, що таке «акуратно» |
| «Коли стане краще» | Це суб’єктивно |
| «Коли код буде чистим» | Так само суб’єктивно |
Добрі умови:
| Хороше формулювання | Чому воно хороше |
|---|---|
завершується без помилок |
Перевіряється машинно |
зелений |
Перевіряється машинно |
| Потрібні тести проходять | Перевіряється машинно |
Приклад у task spec може виглядати так:
## Умова завершення
Задача вважається завершеною, коли:
- RefundControllerTest проходить
- RefundServiceTest проходить
- ./gradlew test завершується з code 0
- публічний API refund endpoint не змінено
Тут є тонкий, але важливий нюанс. Goal-driven режим безпечний лише за детермінованої верифікації. Якщо у вас немає надійних тестів, якщо перевірка суб’єктивна, якщо задача про «на око стало зручніше», запускати такий режим небезпечно. Це вже не інженерний автопілот, а гра в «сподіваюся, ми десь вчасно зупинимося». А надія, як відомо, не входить до офіційного стеку quality assurance.
8. Скрізний приклад: refund-flow у Commerce OS
Щоб усе це не висіло в повітрі, давайте зберемо один цілісний сценарій. Припустімо, у Commerce OS у нас є задача: refactor refund-flow так, щоб decision logic пішла з контролера в сервісний шар, а поведінка лишилася колишньою. Задача не на п’ять хвилин, але й не на два тижні. Класичний кандидат на акуратну довгу сесію.
Каркас може бути таким:
# TASK_SPEC: refund-flow refactor
Мета:
Винести refund decision logic з RefundController у RefundService.
Область:
Лише refund-flow.
Обмеження:
Не змінювати API, не чіпати payment provider integration, зберегти tests green.
Майлстоуни:
M1 — characterization tests
M2 — RefundService extraction
M3 — controller cleanup + verification
Точки зупинки:
Після кожного milestone: summary + checks + commit
Сесію ми називаємо refund-refactor. Branch — feature/refund-refactor. Після першого етапу фіксуємо короткий summary:
## Підсумок майлстоуна: M1
Готово:
- додані тести на approval threshold
- зафіксовано поведінку partial refund
Рішення:
- threshold не переносимо в БД
- payment integration поза scope
Далі:
- виділити RefundService без зміни API
Далі, на другому етапі, вам уже не потрібно знову згадувати, чому threshold не пішов у БД і навіщо ми не чіпаємо інтеграцію. Рішення записане. Контекст не зобов’язаний тягти це лише у своїй історії.
Якщо на другому етапі Claude починає знову пропонувати utility class або лізти в PaymentGatewayClient, ви не сперечаєтеся без кінця. Ви бачите: задача починає виходити за межі рамок. Отже, час зупинитися, подивитися summary і повернути процес у межі milestone. А якщо задача достатньо формалізована й тести надійні, можна задати машинно перевірювану умову завершення саме для цього етапу: наприклад, усі refund-тести зелені, а білд не падає.
У такому режимі довга задача перестає бути безкінечним чатом, який страшно закрити. Вона перетворюється на послідовність невеликих, зрозумілих станів. Кожен стан має ім’я, межі, short summary, зафіксовані рішення і ясний наступний крок. А це вже зовсім інший рівень контролю. І, що особливо приємно, тут Claude справді починає підсилювати розробника, а не тягнути його за собою в хаос із «ще однієї хорошої ідеї».
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ