Разработка через сомнение
Обзор
Уверенный ответ — не то же самое, что верный. В долгих сессиях накапливается контекст, который незаметно превращает допущения в «факты». Разработка через сомнение — это дисциплина материализации ревьюера со свежим контекстом, настроенного опровергать, а не одобрять, — до того, как любой нетривиальный вывод устоится.
Это не /review. /review — вердикт по законченному артефакту. Здесь речь о позиции по ходу дела: нетривиальные решения подвергаются перекрёстному допросу, пока смена курса ещё дёшева.
Когда применять
Решение нетривиально, когда верно хотя бы одно из:
- Оно вводит или меняет ветвящуюся логику
- Оно пересекает границу модуля или сервиса
- Оно утверждает свойство, которое система типов или компилятор проверить не могут (потокобезопасность, идемпотентность, порядок, инварианты)
- Его корректность зависит от контекста, невидимого будущему читателю
- Радиус поражения необратим (выкатка в продакшн, миграция данных, изменение публичного API)
Применяй скилл, когда:
- Собираешься принять архитектурное решение в условиях неопределённости
- Собираешься закоммитить нетривиальный код
- Собираешься заявить неочевидный факт («это безопасно», «это масштабируется», «это соответствует спеке»)
- Работаешь в коде, который понимаешь не до конца
Когда НЕ применять:
- Механические операции (переименование, форматирование, перемещение файлов)
- Следование ясной однозначной инструкции пользователя
- Чтение или пересказ существующего кода
- Однострочные изменения с очевидной корректностью
- Чисто инструментальные операции (прогон тестов, вывод списка файлов)
- Пользователь явно попросил скорость вместо проверки
Если сомневаться в каждом нажатии клавиши, ничего не выпустишь. Скилл применяется только к нетривиальным решениям в определении выше.
Ограничения загрузки
Этот скилл рассчитан на оркестратор основной сессии, где шаг 3 (СОМНЕНИЕ, подробности ниже) может породить ревьюера со свежим контекстом.
- НЕ добавляй этот скилл в раздел
skills:во frontmatter персоны. Персона, следующая шагу 3, породила бы другую персону — это антипаттерн оркестрации, прямо запрещённый в../../references/orchestration-patterns.md(«персоны не вызывают другие персоны»). - Если ты обнаружил, что применяешь этот скилл изнутри контекста субагента (где Claude Code запрещает вложенное порождение субагентов): предпочтительный путь — сообщить пользователю, что разработка через сомнение не может работать вложенно, и передать это основной сессии. Только как крайняя мера существует ослабленный запасной вариант с самоопросом — перепиши АРТЕФАКТ + КОНТРАКТ как свежий промпт самому себе с жёстким мысленным разделителем от предыдущих рассуждений и пройди шаги 1–5. Это не ревью на свежем контексте (свой контекст ты несёшь с собой), поэтому помечай результат как ослабленный и предпочитай эскалацию всегда, когда пользователь доступен.
Процесс
Скопируй этот чеклист при применении скилла:
Цикл сомнения:
- [ ] Шаг 1: УТВЕРЖДЕНИЕ — записано утверждение + почему это важно
- [ ] Шаг 2: ИЗВЛЕЧЕНИЕ — выделены артефакт и контракт, рассуждения убраны
- [ ] Шаг 3: СОМНЕНИЕ — вызван ревьюер со свежим контекстом и состязательным промптом
- [ ] Шаг 4: СВЕДЕНИЕ — каждая находка классифицирована по тексту артефакта
- [ ] Шаг 5: СТОП — выполнено условие остановки (тривиальные находки, 3 цикла или решение пользователя)
Шаг 1: УТВЕРЖДЕНИЕ — назови то, что устоится
Назови решение в две-три строки:
УТВЕРЖДЕНИЕ: «Новый слой кеширования потокобезопасен при
нагрузке с преобладанием чтения, описанной в спеке.»
ПОЧЕМУ ЭТО ВАЖНО: гонка здесь портит данные пользователей и
плохо ловится на тестировании.
Если не можешь записать утверждение так же компактно — у тебя ощущение, а не решение. Сформулируй его, прежде чем разбирать.
Шаг 2: ИЗВЛЕЧЕНИЕ — наименьшая проверяемая единица
Ревьюеру со свежим контекстом нужны артефакт и контракт, а не путь, которым ты к ним пришёл.
- Код: дифф или функция, а не весь файл
- Решение: предложение в 3–5 предложениях плюс ограничения, которым оно должно удовлетворять
- Утверждение: заявление плюс доказательства, которые его якобы подкрепляют (отдельно от блока УТВЕРЖДЕНИЕ из шага 1, который является гипотезой оркестратора, подлежащей разбору)
Убери свои рассуждения. Если передашь выводы, получишь обратно подтверждение своих выводов. Единица должна быть достаточно маленькой, чтобы ревьюер удержал её в голове за одно прочтение: если это PR на 500 строк — сначала декомпозируй.
Шаг 3: СОМНЕНИЕ — вызови ревьюера со свежим контекстом
Промпт ревьюера обязан быть состязательным. Формулировка определяет ответ.
Состязательное ревью. Найди, что не так с этим артефактом.
Исходи из того, что автор самоуверен. Ищи:
- Непроговорённые допущения
- Необработанные краевые случаи
- Скрытую связанность или общее состояние
- Способы нарушить контракт
- Существующие соглашения, которые это может сломать
- Режимы отказа при неожиданном вводе
НЕ подтверждай. НЕ пересказывай. Найди проблемы либо явно
заяви, что после тщательного разбора не смог найти ни одной.
АРТЕФАКТ: <вставь артефакт>
КОНТРАКТ: <вставь контракт>
Передавай только АРТЕФАКТ + КОНТРАКТ. НЕ передавай УТВЕРЖДЕНИЕ. Отдав ревьюеру свой вывод, ты смещаешь его к согласию. Ревьюер должен независимо определить, удовлетворяет ли артефакт контракту.
В Claude Code ролевые ревьюеры в agents/ по замыслу стартуют с изолированным контекстом и пригодны здесь — состав и соответствие по областям см. в agents/.
Состязательный промпт выше имеет приоритет над формой ответа, заданной персоной по умолчанию. Персоны вроде code-reviewer написаны так, чтобы выдавать взвешенный вердикт с сильными и слабыми сторонами, а разработке через сомнение нужен вывод только с проблемами. Вставляй состязательный промпт дословно в вызов, чтобы он перекрыл умолчание персоны. Если форму ответа персоны переопределить чисто не выходит, откатывайся к обычному субагенту с состязательным промптом.
Эскалация на другую модель
Ревьюер той же модели разделяет слепые зоны с автором — более холодная модель другой архитектуры их ловит. Разработка через сомнение и так применяется по выбору для нетривиальных решений, поэтому в её рамках предложение проверки другой моделью — часть ценности скилла, а не необязательное трение.
Интерактивные сессии: предлагай всегда. Никогда не пропускай молча.
Шаг 1: спроси пользователя
После одномодельного ревью из шага 3 выше, но до СВЕДЕНИЯ, остановись и спроси:
«Одномодельное ревью закончено. Нужно второе мнение от другой модели? Варианты: Gemini CLI, Codex CLI, ручное внешнее ревью (вставите сами) или пропустить.»
Этот вопрос обязателен в каждом интерактивном цикле сомнения — даже на артефактах, кажущихся малозначимыми. Пользователь, а не агент, решает, стоит ли оно того. Задача агента — вынести выбор наружу.
Шаг 2: если пользователь выбрал CLI — проверь, потом вызывай
- Убедись, что инструмент есть в PATH (
which gemini,which codex). - Проверь, что он работает (
gemini --versionили аналог), прежде чем передавать полный промпт: устаревший или сломанный бинарник может пройтиwhich, но упасть на реальном вводе. - Согласуй точную команду вызова с пользователем, включая нужные флаги, авторизацию и переменные окружения (например, ключи API). Реализации различаются; никогда не предполагай.
- Передавай только АРТЕФАКТ + КОНТРАКТ + состязательный промпт. Никакого контекста сессии, никакого УТВЕРЖДЕНИЯ.
- Помни про экранирование в оболочке. Если артефакт содержит кавычки,
$(...)или обратные апострофы, предпочитай stdin (echo … | gemini) или heredoc встроенному-p "…". Сомневаешься — попроси пользователя подтвердить команду до запуска. - Возьми вывод в шаг 4 (СВЕДЕНИЕ).
Никогда не подставляй артефакт в аргумент, заключённый в кавычки оболочки. Код, markdown и промпты для ревью регулярно содержат обратные апострофы, $(...) и кавычки, которые либо обрежут промпт, либо выполнят встроенные команды оболочки. Пиши полный промпт в файл и передавай через stdin.
Примерные формы (сверь флаги со своим установленным инструментом — синтаксис различается между реализациями и версиями):
# Сначала запиши состязательный промпт + АРТЕФАКТ + КОНТРАКТ во временный файл.
# Затем передай через stdin, чтобы метасимволы оболочки в артефакте остались инертными.
# Codex (песочница только для чтения не даёт CLI писать в твоё рабочее пространство):
codex exec --sandbox read-only -C <repo-path> - < /tmp/doubt-prompt.md
# Gemini ('--approval-mode plan' — только чтение; '-p ""' включает неинтерактивный
# режим, и промпт читается из stdin):
gemini --approval-mode plan -p "" < /tmp/doubt-prompt.md
Песочница только для чтения — несущая деталь: артефакт для сомнения может сам содержать инструкции (намеренная или случайная инъекция промпта), которые CLI другой модели иначе выполнил бы в твоём рабочем пространстве.
Шаг 3: если CLI недоступен или упал
Явно сообщи о сбое. Предложи: запустить вручную, попробовать другой инструмент или пропустить. Не откатывайся молча к одномодельному варианту — пользователь должен знать, что проверки другой моделью не было.
Шаг 4: если пользователь пропускает
Отметь пропуск в выводе («Продолжаю только с находками одной модели») и переходи к СВЕДЕНИЮ. Пропускать нормально; пропускать молча — нет.
Неинтерактивные контексты (CI, /loop, автономный цикл, запуски по расписанию):
- Проверка другой моделью пропускается, и пропуск должен быть объявлен в выводе: «Проверка другой моделью пропущена: неинтерактивный контекст.»
- Никогда не вызывай внешний CLI без явной авторизации пользователя — это несущее свойство безопасности.
Проверка другой моделью добавляет стоимость, задержку и хрупкость инструментов. Агент выносит выбор наружу в каждом цикле; пользователь решает, заслуживает ли этого данный артефакт.
Шаг 4: СВЕДЕНИЕ — верни находки в работу
Вывод ревьюера — данные, а не вердикт. Оркестратор по-прежнему ты. Перечитай текст артефакта против каждой находки, прежде чем классифицировать: штамповать за ревьюером — тот же способ провалиться, что и игнорировать его.
Классифицируй каждую находку в таком порядке приоритета (побеждает первый подходящий класс):
- Неверно понятый контракт — ревьюер отметил что-то именно потому, что предоставленный тобой КОНТРАКТ был неясным или неполным. Сначала почини контракт, переклассифицируй на следующем цикле.
- Верно и требует действия — настоящая проблема, требующая изменения артефакта. Меняй, повторяй цикл.
- Верно, но это компромисс — проблема реальна, но стоимость исправления выше стоимости принятия. Задокументируй компромисс явно, чтобы пользователь его видел.
- Шум — ревьюер отметил то, что на самом деле корректно в контексте, которого у него не было. Отметь, иди дальше и спроси себя: предотвратило бы добавление этого контекста в контракт ложное срабатывание?
Свежий ревьюер может ошибаться, потому что ему не хватает контекста. Не уступай только потому, что он «свежий».
Шаг 5: СТОП — ограниченный цикл, а не рекурсия
Останавливайся, когда:
- Следующая итерация возвращает только тривиальные или уже рассмотренные находки, или
- Пройдено 3 цикла (эскалируй пользователю, не молоти четвёртый в одиночку), или
- Пользователь явно говорит «выпускаем»
Если после 3 циклов ревьюер всё ещё поднимает существенные проблемы, артефакт, возможно, не готов. Сообщи это пользователю: три неразрешённых цикла — информация об артефакте, а не повод продолжать крутиться.
Если 3 цикла «очевидно недостаточно», потому что артефакт большой, значит артефакт слишком велик — вернись к шагу 2 и декомпозируй. Не поднимай ограничение.
Типовые самооправдания
| Самооправдание | Как на самом деле |
|---|---|
| «Я уверен, пропущу шаг сомнения» | Уверенность плохо коррелирует с корректностью на новых задачах. Моменты убеждённости — ровно те, где прячутся слепые зоны. |
| «Порождать ревьюера дорого» | Отладка неверного коммита в продакшне дороже. Проверка ограничена, баг — нет. |
| «Ревьюер будет только придираться» | Только если не задать рамки. Ограничь промпт «проблемами, из-за которых это провалится по контракту». |
«Посомневаюсь в конце через /review» |
/review — финальные ворота. Разработка через сомнение ловит неверное направление рано, когда смена курса дёшева. К моменту PR уже поздно. |
| «Если сомневаться на каждом шаге, я ничего не выпущу» | Скилл применяется к нетривиальным решениям, а не к каждому нажатию. Перечитай «Когда НЕ применять». |
| «Два мнения всегда лучше одного» | Не тогда, когда у второго меньше контекста и он производит шум. Своди, а не уступай. |
| «Ревьюер не согласился, значит я был неправ» | Ревьюеру не хватает твоего контекста — несогласие это информация, а не вердикт. Перечитай артефакт, классифицируй, потом решай. |
| «Другая модель всегда лучше» | Другая модель ловит слепые зоны, которые одна модель разделяет сама с собой, но добавляет стоимость и хрупкость инструментов. Предлагай её в каждом интерактивном цикле — пользователь решает, заслуживает ли этого артефакт. Задача агента — вынести выбор, а не решить за него. |
| «Пользователь один раз сказал "да", значит можно и дальше вызывать CLI» | Каждый вызов — своя авторизация. Артефакт, промпт и флаги меняются между вызовами: подтверждай точную команду с пользователем перед каждым запуском. |
Тревожные признаки
- Порождение ревьюера со свежим контекстом ради однострочного переименования или форматирования
- Отношение к выводу ревьюера как к авторитету без перечитывания текста артефакта
- Больше 3 циклов без эскалации пользователю
- Промпт ревьюеру в форме «это хорошо?» вместо «найди проблемы»
- Пропуск сомнения под давлением сроков в решении с высокими ставками
- Повторное порождение свежего контекста на неизменившемся артефакте (получишь те же находки; ты тянешь время)
- Театр сомнения (проверяемый сигнал): за 2 и более циклов, где ревьюер поднимал существенные находки, ни одна не была классифицирована как требующая действия. Ты подтверждаешь, а не сомневаешься. Остановись и эскалируй.
- Сомнение только после коммита — это
/review, а не разработка через сомнение - Зашивание команды вызова внешнего CLI без подтверждения от пользователя, что инструмент существует, настроен и принимает именно такой синтаксис
- Молчаливый пропуск проверки другой моделью в интерактивном цикле. Даже когда ты её не рекомендуешь, предложение должно быть видимым. Пропускать нормально; пропускать молча — нет.
- Молчаливый откат при ошибке или отсутствии внешнего CLI — сообщи о сбое и дай пользователю перенаправить
- Отсечение контракта из входных данных ревьюера
- Передача УТВЕРЖДЕНИЯ ревьюеру (смещает к согласию)
Взаимодействие с другими скиллами
code-review-and-quality//review: дополняют друг друга./review— постфактумный вердикт по PR; разработка через сомнение — по ходу дела на каждое решение. Используй оба.source-driven-development: SDD проверяет факты о фреймворках по официальной документации. Разработка через сомнение проверяет твои рассуждения об артефакте. SDD убеждается, что API существует; сомнение убеждается, что ты использовал его корректно по контракту.test-driven-development: шаг RED в TDD — это сомнение, воплощённое конкретно: падающий тест есть попытка опровержения. Когда TDD применим, этот падающий тест и есть шаг сомнения для утверждений о поведении.debugging-and-error-recovery: когда ревьюер вскрывает настоящий режим отказа, переходи в скилл отладки, чтобы локализовать и починить.- Правила оркестрации репозитория (
../../references/orchestration-patterns.md): этот скилл оркестрирует из основной сессии. Персона, вызывающая другую персону, — антипаттерн B, см. «Ограничения загрузки» выше.
Проверка
После применения разработки через сомнение:
- Каждое нетривиальное решение (по определению выше) было явно названо как УТВЕРЖДЕНИЕ, прежде чем устояться
- Хотя бы одно ревью на свежем контексте на каждый нетривиальный артефакт (падающий тест из шага RED в TDD удовлетворяет этому для утверждений о поведении, см. «Взаимодействие с другими скиллами»)
- Ревьюер получил АРТЕФАКТ + КОНТРАКТ — НЕ УТВЕРЖДЕНИЕ и НЕ твои рассуждения
- Промпт ревьюера был состязательным («найди проблемы»), а не подтверждающим («это хорошо?»)
- Находки классифицированы по тексту артефакта (а не проштампованы) в порядке приоритета: неверно понятый контракт / требует действия / компромисс / шум
- Выполнено условие остановки (тривиальные находки, 3 цикла или решение пользователя)
- В интерактивном режиме проверка другой моделью была явно предложена пользователю (независимо от ставок артефакта), и ответ отражён в выводе
- В неинтерактивном режиме проверка другой моделью пропущена, и пропуск объявлен
- Любому вызову внешнего CLI предшествовали проверка PATH, тест работоспособности бинарника, согласование синтаксиса с пользователем и явная авторизация на запуск