Урок 3

Совет — зная это, вы уже можете командовать

Четыре фразы — это всё.

Агенту: “Создай Hurl-тест” ИИ напишет контракт, проверяющий правильность работы функции. Plain text, который можно прочитать без навыков программирования.

Агенту: “Добавь эту функцию. Но существующие Hurl-тесты должны проходить” Эта одна фраза предотвращает дрифт. Если ИИ при добавлении новой функции сломает существующую — Hurl сообщит красным текстом.

Агенту: “Закоммить” Сохранение рабочего состояния. Как точка сохранения в игре. Если следующая задача провалится — возврат сюда.

Агенту: “Откати” Возврат к последней точке сохранения. Восстановление того, что ИИ сломал.

Паттерн этих четырёх фраз

Функция готова → “Создай Hurl-тест” → Проверка прохождения → “Закоммить” → Следующая функция → “Существующие Hurl должны проходить” → При проблеме “Откати”

Это храповик. Шестерёнка, идущая только вперёд. Будь функций 5 или 50 — существующие не ломаются.

Почему это работает?

В уроке 2 мы узнали: дайте ИИ мнение — получите лесть, дайте факт — получите исправление. То, что возвращает Hurl — не мнение, а факт. “test failed: status 401, expected 200” — здесь нечему льстить.

Быстрый старт

Создайте один Hurl-тест для приложения задач из практики урока 2. Это займёт 3 минуты.

Агенту: “Напиши Hurl-тест, проверяющий правильность работы текущей функции добавления задач”

ИИ создаст файл .hurl.

Агенту: “Запусти Hurl-тест”

Если прошёл — зелёный. Теперь намеренно сломаем.

Агенту: “Переименуй id в todo_id в ответе API добавления задач”

Агенту: “Запусти Hurl-тест”

Красный текст — провал. Это обнаружение дрифта.

Агенту: “Откати”

Снова зелёный. Вот суть храповика.


Почему нужно командовать именно так

В уроке 2 мы увидели проблемы: логический дрифт, потеря контекста, предвзятость лести. После 5 функций существующие ломаются, а ИИ ложно заявляет “всё работает”.

В этом уроке мы изучим три инструмента для предотвращения. Все они десятилетиями используются инженерами. Не нужно уметь читать код. ИИ пишет и запускает. Вам достаточно спросить: “Прошло?”

Роли трёх инструментов:

ИнструментАналогияЧто делает
HurlКонтрактОбъявляет “эта функция должна работать так”
GitТочка сохраненияГарантирует “можно вернуться к этому моменту”
CI/CDАвтоматическая камера наблюденияМеханизирует “проверяется каждый раз автоматически”

Hurl — объявление API-контракта в plain text

Что такое Hurl

Hurl — это файл, описывающий “как должен работать этот API”.

По аналогии с игрой: в RPG покупка зелья у NPC имеет правило “1 зелье → -50 золота, +100 здоровья”. Hurl проверяет, что это правило не изменилось после патча.

Реальный файл Hurl:

# Добавление задачи
POST http://localhost:8080/api/todos
{
  "title": "Купить молоко",
  "priority": "high"
}
HTTP 201
[Asserts]
jsonpath "$.id" exists
jsonpath "$.title" == "Купить молоко"
jsonpath "$.priority" == "high"
jsonpath "$.completed" == false

Читается даже без навыков программирования:

  • POST — запрос “добавь” серверу
  • http://localhost:8080/api/todos — адрес списка задач
  • { “title”: “Купить молоко” } — отправляем такие данные
  • HTTP 201 — при успехе должен прийти ответ 201
  • jsonpath “$.title” == “Купить молоко” — в ответе должно быть “Купить молоко”

Это контракт. “При добавлении задачи приходит 201, название и приоритет возвращаются как есть.” Если контракт нарушен — Hurl сообщает красным текстом.

Ещё один пример:

# Доступ без авторизации — отказ
GET http://localhost:8080/api/todos
HTTP 401

“При доступе к списку задач без логина должен прийти 401 (требуется аутентификация).” Это тоже контракт. Если ИИ “наведёт порядок” в коде авторизации и сломает это правило — Hurl поймает мгновенно.

Почему Hurl — отличие от юнит-тестов

“Инструментов тестирования много, почему именно Hurl?” Для вайб-кодера есть особая причина.

Юнит-тесты проверяют внутренние функции кода. Аналогия с автомобилем: юнит-тест — разборка и проверка каждой детали двигателя, Hurl — дорожные испытания. Если изменилось имя функции, ломается и тест, и при рефакторинге ИИ должен менять оба. Если дать ИИ право менять и код, и тесты, ИИ подгонит тесты под код. Тесты проходят, но изначальное правило исчезло.

Hurl — иначе. Он проверяет на входе. Отправляет запрос, проверяет ответ. Не знает внутреннюю структуру кода. Как бы ИИ ни менял код — если наблюдаемое поведение такое же, тест проходит, если другое — провал.

Юнит-тестыHurl
АналогияРазборка деталей двигателяДорожные испытания
Если ИИ меняет кодТест тоже может изменитьсяТест остаётся, проверяется только результат
Сложность чтенияНужно знать кодЧитается как обычный текст
Обнаружение дрифтаЕсли ИИ изменит и тест — пропуститНезависим от кода, обнаруживает естественно

Hurl проверяет не код, а поведение. Код ИИ может менять свободно. Поведение меняться не должно. Это различие — ключ к обнаружению дрифта.

Почему это эффективно — доказано исследованиями

В уроке 2 мы узнали о предвзятости лести. Совет “пиши тесты” тоже зависит от формулировки.

Исследование TDAD (Test-Driven AI Development, 2026) точно это проверило. ИИ исправлял баги при разных условиях тестирования:

УсловиеРегрессия (% поломки существующих функций)
Базовое (без указаний по тестам)6,08%
Процедурное указание “делай TDD”9,94% (ухудшение!)
Предоставление файла затронутого теста в контексте1,82% (снижение на 70%)

Удивительный результат. “Делай TDD” — ухудшает. ИИ путается, пытаясь следовать процедурному указанию. Но “этот тестовый файл должен проходить” — конкретный контекст — снижает регрессию на 70%.

Разница ясна:

  • “Разрабатывай с тестами” → процедурное указание → ИИ путается
  • “Этот Hurl-файл должен проходить” → конкретный контракт → регрессия -70%

Не указание метода, а контракт — что должно проходить. Именно об этом “фраза 3” выше.

Git — точка сохранения с возможностью отката

Что такое Git

В играх делают сохранения. Перед боссом — сохранение, проиграли — загрузка.

Git — это функция сохранения для кода. “Сейчас всё работает” → сохранение (коммит). Следующая задача провалилась → возврат к предыдущему сохранению.

Вайб-кодинг без Git:

Функция 1 → работает
Функция 2 → работает
Функция 3 → функция 1 сломалась!
→ Хочу откатить... а какое было состояние функции 2?
→ ИИ: "вернуть к тому, что было" → ИИ не знает, что было "то"
→ Начинаем сначала

С Git:

Функция 1 → работает → коммит (сохранение 1)
Функция 2 → работает → коммит (сохранение 2)
Функция 3 → функция 1 сломалась!
→ "Вернись к сохранению 2" → функции 1 и 2 работают
→ Пробуем функцию 3 другим способом

Git: достаточно двух слов

Не нужно учить десятки команд Git. Вайб-кодеру нужны две вещи.

“Закоммить” — сохранить текущее состояние

"Закоммить текущее состояние. Сообщение — 'Функция добавления задач готова'"

“Откати” — вернуться к предыдущему состоянию

"Откати к последнему коммиту"

Когда коммитить

Правило простое:

  1. Функция готова и работает → коммит
  2. Все Hurl-тесты проходят → коммит
  3. Перед началом следующей функции → обязательно коммит

Без коммита — при проблеме некуда вернуться. Как 3 часа игры без сохранения.

Аналогия Git: базовые лагеря при восхождении

На Эверест не лезут за один раз. Базовый лагерь → Лагерь 1 → Лагерь 2 → … → вершина. В каждом лагере ставят палатку и накапливают запасы. При плохой погоде спускаются в предыдущий лагерь. Без лагерей в шторм — гибель.

Git-коммиты — это лагеря. При каждой готовой функции — лагерь. Если ИИ сломает следующую функцию — можно вернуться в предыдущий.

CI/CD — машина охраняет автоматически

Что такое CI/CD

CI (Continuous Integration) — автоматический запуск тестов при каждом обновлении кода. CD (Continuous Deployment) — автоматический деплой при прохождении тестов.

Сейчас достаточно знать CI. CD — потом.

Без CI:

Вы:      "Добавь функцию"
ИИ:      "Готово!"
Вы:      (на экране проверяете только новую функцию) "Работает!"
→ Не замечаете, что существующая функция сломана

С CI:

Вы:      "Добавь функцию"
ИИ:      (пишет код)
Машина:  (автоматически запускает все Hurl-тесты)
Машина:  "Тест логина провален!"
Вы:      "Логин сломан. Почини."
ИИ:      (исправляет)
Машина:  "Все тесты пройдены"
Вы:      "Закоммить"

Вам не нужно запускать Hurl-тесты вручную каждый раз. Машина делает это автоматически.

CI как пожарная сигнализация

В здании есть пожарная сигнализация. При пожаре — автоматически срабатывает. Охранник не нужен для круглосуточного обхода.

CI — пожарная сигнализация кода. Если Hurl-тесты ломаются — автоматическое уведомление. Вам не нужно проверять вручную каждый раз.

Три инструмента вместе: храповиковая фиксация

Hurl + Git + CI дают храповик (ratchet). Храповик — шестерёнка, вращающаяся только в одну сторону. Повернул — вперёд, отпустил — стоит, но назад не идёт.

Функция 1 готова → Hurl-тест → всё проходит → коммит → фиксация
Функция 2 готова → Hurl-тест добавлен → старые + новые проходят → коммит → фиксация
Функция 3 в работе → старый Hurl-тест провален → коммит отклонён → исправление → всё проходит → коммит → фиксация

Правила просты:

  1. Прошедший Hurl-тест — фиксируется
  2. Зафиксированные тесты нельзя удалять/менять
  3. При новой функции — новый Hurl-тест тоже
  4. Все старые + все новые тесты должны пройти для коммита

Если сказать ИИ “отрефактори код”, ИИ свободно меняет код. Но если Hurl-тест провалится — коммит отклоняется. ИИ обязан сохранять всё существующее поведение.

Это точно совпадает с результатом исследования TDAD. Не процедурное указание “пиши тесты”, а конкретный контракт “этот Hurl-файл должен проходить”. Агент может выбирать метод, но не может нарушить контракт.

Как решаются проблемы урока 2

Проблема урока 2Решение урока 3
Логический дрифтHurl защищает существующее поведение. Поведение изменилось — провал
Потеря контекстаHurl-файлы сохраняют решения навсегда. Сессия сменилась — контракт остался
Предвзятость лести (“всё готово”)CI судит механически. Не самоотчёт ИИ, а pass/fail
Смешение решений и реализацииHurl объявляет решения (поведение) в отдельном файле от кода
Умножение деградацииХраповиковая фиксация на каждом шаге сбрасывает деградацию

Итоги

Что мы изучили:

  1. Hurl — объявляет контракт “должно работать так” в plain text. Проверяет не код, а поведение
  2. Git — создаёт точку сохранения “можно вернуться”
  3. CI/CD — устанавливает механическую проверку “автоматически каждый раз”
  4. Храповик — три вместе дают “прошёл — зафиксирован, назад не идёт”

Ключевой принцип:

Не указывайте ИИ метод. Дайте контракт — что должно проходить.

“Делай TDD” → регрессия ухудшается. “Этот Hurl должен проходить” → регрессия -70%. Разница между указанием и контрактом.

Не меняйте модель, добавьте контракт.


Анонс следующего урока

В уроке 3 мы научились защищать каждый API через Hurl. Но при росте проекта защищать нужно не только API. Структура БД, политики безопасности, UI-компоненты — всё должно быть согласовано.

В уроке 4 изучим yongol. Управление API, БД, безопасностью, UI через единую декларативную спецификацию. Перенос объекта работы ИИ с кода на спецификацию. Метод преодоления барьера 200 эндпоинтов.


Связанные статьи


Полный курс Reins Engineering

УрокНазвание
Урок 1Как командовать ИИ
Урок 2Как не доверять ИИ
Урок 3Нерушимое приложение
Урок 4Решения — за пределы кода
Урок 5ИИ на поводьях
Урок 6Прошёл — зафиксировал
Урок 7Как обратить лесть
Урок 8Фабрика агентов
Урок 9Автоматизация за пределами кода
Урок 10Закон данных

Источники

  • TDAD (Test-Driven AI Development) 2026 — процедурное указание “делай TDD” ухудшает регрессию до 9,94%, предоставление тестового файла в контексте снижает регрессию до 1,82% (-70%)
  • Эксперимент Ratchet Pattern — автономный агент 40/527 (7,6%) vs храповик CLI 527/527 (100%), та же модель, разница в том, кто определяет завершение