JavaRush /Курсы /Claude code /Constraints и границы изменений

Constraints и границы изменений

Claude code
3 уровень , 4 лекция
Открыта

1. Без constraints task spec остаётся проблемным

После Goal, Current behavior, Desired behavior, Scope, Non-goals и Affected area черновик держит задачу: понятно, что меняется и где. Остаётся дыра — как именно Claude работает внутри этой зоны. Агент честно остаётся внутри refund flow и приносит лишнее: новую зависимость, широкий рефакторинг, правку старых миграций, догадку вместо проверки схемы. Для этого нужны constraints — цель они не меняют, ограничивают способ её выполнения.

Claude ломает проекты не со зла, а от усердия. Вы просили поле notes — получаете ещё и новый пакет для rich-text редактора, «заодно» переработанный RefundService, схему события, пару переименований и косметику по всему неровному. Формально полезно. Практически — открываете diff и хватаетесь за голову.

Слабая постановка:

Добавь поле `notes` в refund-request и сохрани его.

Постановка с первыми нормальными границами:

Добавь опциональное поле `notes` в refund-request.
Не меняй public API refund endpoints, кроме безопасного расширения payload.
Не добавляй зависимости.
Не трогай payment processing и approval thresholds.
Сначала предложи план, потом вноси изменения.

Во втором варианте вы задаёте периметр движения. Constraints отвечают не на «что сделать», а на «какие способы нам не подходят» — часто это важнее. Goal даёт направление, scope — территорию, constraints — таблички «сюда не заезжать». Без них задача понятна, но слишком свободна.

2. Constraints vs goal, scope и non-goals

Легко решить, что goal, scope, non-goals и constraints разными словами говорят «не делай ерунду». У каждого блока своя работа.

Блок На какой вопрос отвечает Как выглядит в задаче F-03
Goal Что должно измениться и зачем У оператора появляется поле notes, заметка сохраняется и видна в карточке возврата
Scope Где можно работать Форма refund-request, detail view, RefundService, событие refund.created, связанные тесты
Non-goals Что сознательно не делаем Не меняем пороги авто/ручного approval, не трогаем оплату, не рефакторим соседние модули
Constraints Как нельзя выходить за границы изменений Не менять public API, не добавлять зависимости, не делать broad refactor, сначала предложить план

- Goal — что меняем.

- Scope — где меняем.

- Non-goals — что не меняем.

- Constraints — как не нарушить границы, пока меняем.

Тоньше всего разница non-goals и constraints. Non-goals — про область («не трогаем payment processing»). Constraints — про правило изменения, даже если Claude сочтёт иначе «логичнее» («не добавлять зависимости без одобрения»).

Иногда фраза стоит на границе. «Одна новая миграция и никаких правок старых» читается и как область, и как правило. Помогает вопрос: зачем вы добавляете эту строку? Чтобы не расползлась тема — это non-goals. Чтобы ограничить способ изменения и риск — это constraints.

3. Жёсткие ограничения для нашей задачи в Commerce OS

Не каждая задача требует тяжёлого набора ограничений. Опечатку в заголовке кодексом не обкладывают. Но задача с формой, сохранением данных, событием и базой — другое дело: тут constraints экономят нервные клетки.

Для маленькой задачи хватит tiny spec:

Исправь опечатку в заголовке refund detail view.
Не меняй логику и стили за пределами этого компонента.
Покажи diff после изменения.

Но F-03 — не tiny spec: UI, backend, сохранение записи, событие, потенциально миграция базы. Ограничения нужны явнее:

## Ограничения

- не менять public API refund endpoints; payload расширять только безопасно;
- не добавлять новые зависимости; использовать существующий стек форм и валидации;
- не трогать обработку платежей и пороги approval возвратов;
- не менять не связанные миграции базы; при необходимости создать только одну новую миграцию;
- держать diff небольшим и reviewable; без широкого рефакторинга RefundService;
- сохранить обратную совместимость для существующих возвратов без notes.

Почему именно эти строки:

Public API — внешний контракт для других частей системы и клиентов. Тихо поменяли структуру ответа endpoint — сломали фронтенд и интеграции. Расширять payload безопасно: новое поле можно, старое поведение ломать нельзя.

Dependency — внешняя библиотека. Решать каждую задачу новым пакетом соблазнительно, но на реальном коде это шкаф с плохо подписанными коробками.

Migration — изменение структуры базы. Нужно новое поле — одна миграция; старые, не связанные с задачей, не трогаем.

Diff — изменения «до/после»; reviewable — человек спокойно читает и проверяет. Одно поле разрослось в двадцать файлов и helper на полэкрана — задача потеряла форму. Claude счастлив, ревьюер нет.

4. Constraints бывают и поведенческими

Под constraints обычно представляют запреты: «не меняй», «не трогай». Но часть самых полезных — про ритм работы, а не запрет. Они делают поведение Claude предсказуемым.

## Рабочие ограничения

- сначала изучи текущую схему и затронутые файлы, потом редактируй;
- сначала предложи короткий план;
- если что-то неоднозначно, задавай вопросы вместо догадок;
- после реализации перечисли изменённые файлы, выполненные проверки и оставшиеся риски.

Ни слова про «запрещено» — но это всё равно constraints: они задают границы поведения. Claude не прыгает в код, пока не понял схему; не гадает молча; не пишет «готово» и не исчезает в закат.

Это полезно, пока вы не уверенно чувствуете проект. Пинг-понг превращается в цикл: исследуй, изложи план, меняй, отчитайся. Скучно — в этом и сила: предсказуемый процесс спасает проект чаще «креативного прорыва». «Если не уверен — спроси» — не слабость, а запрос на меньше галлюцинаций. Хороший обмен.

5. Правила в CLAUDE.md и TASK_SPEC.md

Начнёте писать ограничения — встаёт вопрос: куда какую фразу складывать? Часть правил повторяется от задачи к задаче, часть нужна один раз. Всё в TASK_SPEC.md — он разрастётся; всё в CLAUDE.md — задача размывается.

Где живёт правило Для чего подходит Пример
CLAUDE.md
Стабильные правила всего проекта «Используем существующий стек», «не трогаем .env», «показывай changed files после правок»
TASK_SPEC.md
Ограничения только для этой задачи «Не менять approval thresholds», «одна новая миграция», «сохранить backward compatibility для refunds без notes»
Session/permission boundary Что Claude вообще может делать в этой сессии Например, режим без самостоятельных правок
Автоматические технические границы Реальная жёсткая блокировка действий Блокировка чувствительных путей, обязательные проверки перед приёмкой

Нас интересуют первые два уровня. Правило: повторяется во всех задачах — место в CLAUDE.md; нужно только для конкретной — TASK_SPEC.md.

В CLAUDE.md:

## Правила проекта

- используй существующие паттерны Spring Boot и React;
- не добавляй зависимости без согласования;
- всегда сообщай об изменённых файлах и выполненных командах;
- никогда не трогай `.env` и файлы с секретами.

А это уже про конкретную F-03 — в TASK_SPEC.md:

## Ограничения

- не менять пороги approval возвратов;
- создать только одну миграцию для `notes`, если требуется изменение схемы;
- сохранить существующее поведение карточки возврата для старых записей.

Важно: constraints — не жёсткая блокировка. «Не трогай оплату» не бетонная стена, Claude теоретически всё равно может полезть не туда. Писать бесполезно? Нет: это дорожный знак — отбойник он не заменяет, но без него хуже. Мы ставим знаки и рисуем разметку, и этого уже достаточно, чтобы задача стала намного безопаснее.

6. Финализируем TASK_SPEC.md для F-03

Соберём рабочий черновик целиком. Тот же F-03, но в нём сошлись целевой результат, текущее и желаемое поведение, поверхность изменений и ограничения. Он не описывает всё на свете — даёт Claude понятный инженерный вход без конкурирующих шаблонов.

# TASK_SPEC.md

## Цель
Разрешить оператору добавлять необязательное поле `notes` при создании
refund-request в административном интерфейсе. Заметка должна сохраняться
вместе с записью возврата, отображаться в деталях возврата и попадать в
payload события `refund.created`, чтобы финансовый ревьюер видел контекст
решения при последующем аудите. Текущая логика порогов авто- и ручного
подтверждения возврата не меняется.

## Текущее поведение
Оператор создаёт refund-request из `admin/orders/{id}`.
Нет поля, чтобы приложить контекстную заметку, например:
«клиент позвонил, согласовали частичный возврат».

Сейчас заметка хранится в отдельном комментарии к саппорт-тикету
и не связана с записью возврата.

В итоге финансовые ревьюеры не видят логику оператора
при последующем аудите возвратов.

## Желаемое поведение
- форма refund-request в `admin/orders/{id}` содержит необязательное поле `notes`
  (textarea, до 1000 символов);
- при отправке формы `notes` сохраняется вместе с записью возврата;
- в карточке возврата заметка отображается в отдельной секции;
- payload события `refund.created` содержит поле `notes`;
- существующие возвраты без заметки рендерятся корректно, без ошибок.

## Область изменений
- форма запроса возврата в админке;
- экран деталей возврата;
- сохранение поля `notes` в записи refund;
- включение `notes` в событие `refund.created`;
- обновление связанных тестов и короткой внутренней документации.

## Не-цели
- не менять пороги auto/manual approval;
- не трогать обработку платежей и интеграцию с PSP;
- не менять логику связывания тикета и возврата;
- не рефакторить `RefundService` за пределами нового поля;
- не править форматирование вне перечисленной зоны задачи.

## Затронутая область (предварительно)
- форма возврата;
- экран деталей возврата;
- `RefundController` / `RefundService`;
- событие `refund.created`;
- схема `refunds` / новая миграция, если поле ещё отсутствует;
- тесты refund flow.

## Ограничения
- не менять public API refund endpoints; payload расширять только безопасно;
- не добавлять новые зависимости; использовать существующий стек форм и валидации;
- не менять не связанные миграции базы; при необходимости создать только одну новую миграцию;
- держать diff небольшим и reviewable; без широкого рефакторинга `RefundService`;
- сохранить обратную совместимость для существующих возвратов без notes;
- сначала изучи текущую схему и затронутые файлы, потом редактируй;
- сначала предложи короткий план;
- если что-то неоднозначно, задавай вопросы вместо догадок;
- после реализации перечисли изменённые файлы, выполненные проверки и оставшиеся риски.

В таком виде черновик уже держит задачу целиком: сначала видно результат, потом разрыв между текущим и целевым состоянием, затем поверхность изменений и, наконец, правила, которые не дают работе расползтись. Этого достаточно, чтобы Claude начал разбирать задачу не вслепую.

Если по пути остаются непроверенные версии вроде «колонка, возможно, уже есть», их удобно держать как рабочие заметки для исследования до проверки, а не превращать в обязательные постоянные заголовки. Формальные критерии приёмки и полный план проверки — это отдельный слой над этой же заготовкой, а не повод переписывать её заново.

И вот здесь task spec окончательно перестаёт быть просьбой «будь умницей» и становится нормальной инженерной постановкой. Не идеальной, не магической, не самодостаточной без человека — но достаточно чёткой, чтобы Claude работал внутри понятных границ, а вы потом не удивлялись, откуда в задаче на одно поле взялся diff на полквартала.

1
Задача
Claude code, 3 уровень, 4 лекция
Недоступна
Изменение лимита заметки без добавления нового стека
Изменение лимита заметки без добавления нового стека
1
Задача
Claude code, 3 уровень, 4 лекция
Недоступна
Классификация правил по месту действия
Классификация правил по месту действия
1
Опрос
Task spec для Claude Code, 3 уровень, 4 лекция
Недоступен
Task spec для Claude Code
Task spec для Claude Code
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ