Единица работы с Codex - не длинный prompt и не красивый diff, а контракт результата. Сильный запрос для агента не обязан быть длинным; он должен снять четыре вида неопределённости: какой результат ожидается, где проходит граница, какое нужно доказательство и какие решения агент вправе принять сам. Расплывчатое "сделай авторизацию лучше" не снимает ни одной из этих неопределённостей - и почти гарантированно приводит к дрейфу, где агент меняет много, а проверить нечего.
Первая неопределённость - результат. Его формулируют как наблюдаемое поведение, а не как алгоритм печатания кода. "Добавить идемпотентность для POST /payments" - это результат; "перепиши обработчик" - это указание способа, которое связывает агенту руки и мешает найти более простое решение. Чем яснее описан желаемый конечный эффект и чем меньше диктуется путь к нему, тем выше шанс, что агент выберет разумную реализацию, а не буквально исполнит вашу догадку.
Вторая неопределённость - граница. Явно назвать, что менять нельзя и какие интерфейсы сохранить, дешевле, чем потом откатывать лишнее. "Не менять публичную схему ответа и движок базы данных" - это граница, которая удерживает изменение в безопасных пределах. Без неё агент склонен "заодно" тронуть смежное, и первая же такая правка на важном контракте создаёт больше работы и риска, чем экономит время.
Третья и четвёртая неопределённости - доказательство и право на решения. Проверку задают конкретно: targeted integration-тест плюс typecheck, а не "убедись, что работает". А право на решения ограничивают явным стоп-условием: если нужен новый dependency или миграция - остановись и объясни выбор, не принимай его молча. Это превращает потенциально необратимое решение в точку контроля, где вы успеваете вмешаться до, а не после.
Полезно один раз увидеть такой контракт целиком. Ниже - компактная форма: что нужно, что не менять, с чего начать исследование, чем проверять, где остановиться и что дать в финале - файлы, поведение, проверки, оставшиеся риски. К этой форме возвращаются каждый раз, когда рука тянется написать одну расплывчатую фразу: пять минут на контракт дешевле, чем разбор красивого, но неверного diff, к которому привёл запрос без критерия.
Важное правило - не диктовать неподтверждённое решение как факт. Если корневая причина ещё неизвестна, а вы уже задали реализацию, агент послушно её выполнит, даже если она мимо. Правильнее сначала попросить исследование без изменений: проследить текущий request flow и найти существующие transaction helpers, а уже потом выбирать. Дать агенту начать с реального кода, а не с вашей гипотезы, - лучший способ избежать красивого решения не той задачи.
Источник истины важнее его пересказа. Воспроизводимый падающий тест сильнее слов "иногда падает", точный лог сильнее пересказа ошибки, схема API или определение типа сильнее догадок о формате. Чем ближе агент к первичным данным, тем меньше он домысливает. Контракт как раз и направляет его к источнику: "сначала найди flow и helpers" - это указание идти к коду, а не строить решение на предположении о том, как всё устроено.
Типичные провалы вокруг контракта предсказуемы. Расплывчатая цель без наблюдаемого результата, из-за которой агент дрейфует. Отсутствие границы, открывающее лишние файлы и контракты. Проверка "убедись, что работает" вместо конкретной команды. И молчаливое принятие необратимого решения без стоп-условия. Снимайте все четыре неопределённости - результат, граница, доказательство, право на решения - и запрос превращается из пожелания в задачу с однозначным признаком выполнения.
Нужно: добавить idempotency для POST /payments.
Не менять: public response schema и database engine.
Сначала: найди текущий request flow и существующие transaction helpers.
Проверка: targeted integration test + typecheck.
Если нужен новый dependency или migration - остановись и объясни выбор.
Финал: files, поведение, проверки, оставшиеся риски.