Харнесс-инженерия против Spec-Driven Development: зачем нужно и то, и другое
Spec-driven development отвечает на вопрос «что именно должно сделать это изменение». Харнесс-инженерия отвечает на другой вопрос: «как сделать так, чтобы любое изменение можно было дёшево проверить». Первое без второго превращается в документ, который никто не проверяет. Второе без первого — в зелёный конвейер, нацеленный не туда. Команды, которые всерьёз пишут код с ИИ-агентами, нуждаются в обоих подходах: спецификация задаёт намерение, а харнесс принуждает к нему и проверяет результат.
Что такое харнесс-инженерия
Харнесс — это всё в ИИ-агенте, кроме модели: инструменты, контекст, ограничения и проверки. Биргитта Бёкелер из martinfowler.com даёт короткое определение: «всё в ИИ-агенте, кроме самой модели». Отсюда формула: агент = модель + харнесс.
Показательный пример — публикация OpenAI в феврале 2026 года. Команда Райана Лопополо за пять месяцев выпустила внутренний продукт примерно на миллион строк кода и полторы тысячи смерженных pull request — без единой строки, написанной руками. Формула команды умещается в четыре слова: люди рулят, агенты исполняют. Из отчёта выделяются четыре практики:
- Репозиторий — единственный источник правды (system of record). Всё, что агент не может прочитать во время работы, для него не существует.
- AGENTS.md — оглавление примерно на 100 строк, а не энциклопедия.
- Инварианты — правила, которые нельзя нарушать, — проверяются механически, а сообщения линтеров написаны как инструкции по исправлению.
- Беспорядок в коде чистят непрерывно: фоновые PR на рефакторинг, «как сборка мусора».
Anthropic в статьях ноября 2025 и марта 2026 года разбирает харнесс для долгоживущих агентов: агент-инициализатор готовит окружение и пишет init.sh, а в сложных сценариях работа делится между планировщиком, генератором и оценщиком. Оценщик сверяет результат с заранее согласованными критериями.
Четыре слоя вокруг модели
Адди Османи (июнь 2026) выстраивает практики работы с агентами в четыре вложенных слоя — каждый включает предыдущий:
| Слой | Что вы проектируете | Типичный артефакт |
|---|---|---|
| Prompt engineering | одну инструкцию на один запрос | хорошо структурированный промпт |
| Context engineering | какие токены попадают в окно | правила поиска, сжатие истории, подобранные примеры |
| Харнесс-инженерия | инструменты, ограничения и проверки вокруг агента | AGENTS.md, линтеры, структурные тесты, CI-гейты |
| Loop engineering | что агент делает дальше и когда останавливается | триггеры, верификаторы, правила остановки, лимиты повторов |
Спецификация — не пятый слой. Она — вход для всех четырёх: промпт её цитирует, контекст её включает, харнесс по ней проверяет, а цикл по её критериям решает, когда работа закончена.
Два подхода, два разных вопроса
| Spec-driven development | Харнесс-инженерия | |
|---|---|---|
| Вопрос | Что должно сделать это изменение? | Как сделать любое изменение проверяемым? |
| Масштаб | одно изменение или фича | весь репозиторий, на всю его жизнь |
| Артефакты | spec.md, tasks.md, критерии приёмки, evidence.md | AGENTS.md, документация, линтеры, структурные тесты, тест-харнесс, CI |
| Когда меняется | с каждой новой фичей | когда одна и та же ошибка повторилась дважды |
| Какой риск убирает | агент додумал пропущенное требование | вывод агента тихо ухудшает кодовую базу |
| Что будет без него | команда спорит о задуманном поведении на ревью | команда согласна насчёт поведения, но не может дёшево это доказать |
Где подходы встречаются
Бёкелер делит компоненты харнесса на два типа:
- Гайды работают «до»: предугадывают поведение агента и направляют его до того, как он начнёт действовать.
- Сенсоры работают «после»: наблюдают за результатом и помогают агенту исправиться самому.
Каждый тип бывает вычислительным — тесты, линтеры, проверка типов — или рассуждающим, когда оценкой занимается другая модель, например ИИ-ревью кода. Спецификация в этой схеме — гайд. Причём единственная часть харнесса, которая меняется от фичи к фиче: всё остальное настраивается один раз и работает долго.
Между разделами спецификации и контролами харнесса есть прямое соответствие:
| Раздел спецификации | Контроль в харнессе | Тип |
|---|---|---|
| Контекст, цель, non-goals | ссылка из AGENTS.md, чтобы агент прочитал спеку первым | гайд |
| Allowed files | CI падает, если diff трогает что-то ещё | вычислительный сенсор |
| Критерии AC-1…AC-n | минимум один тест упоминает каждый критерий, иначе CI падает | вычислительный сенсор |
| Edge cases | фикстуры и фабрики данных, воспроизводящие их | тест-харнесс |
| API-контракт | контрактные тесты из OpenAPI-документа | вычислительный сенсор |
| Evidence | раздел в шаблоне PR с именами тестов и логами | ИИ-ревью |
| Rollback | фича-флаг существует и по умолчанию выключен | вычислительный сенсор |
Пример: повторная попытка возврата денег
Спека на эндпоинт возврата с повторной попыткой:
- AC-1: при таймауте шлюза возврат повторяется один раз с тем же ключом идемпотентности.
- AC-2: при втором таймауте возврат остаётся в статусе «в ожидании», дубликата refund_id нет.
- AC-3: каждая попытка пишет событие в аудит-лог.
- Allowed files:
src/billing/refund-worker.ts,tests/refund-worker.test.ts,specs/active/refund-retry/evidence.md.
Без харнесса агент пишет правдоподобный цикл повторов и тест, в котором мок шлюза со второй попытки отвечает успехом. AC-2 не проверяется никогда — но тест зелёный. Заодно агент добавляет хелпер в src/billing/ledger.ts, потому что так «аккуратнее». Все три ошибки находит человек на ревью — поздно и дорого.
С харнессом три сенсора срабатывают до ревью. Гейт по Allowed files ловит изменение ledger.ts — и сборка падает. Проверка критериев сообщает: ни один тест не упоминает AC-2. А мок шлюза живёт в тест-харнессе, а не выдумывается под каждый тест, — в нём есть готовое состояние «дважды таймаут», и недостающий тест стоит агенту одну строку. Спека задала намерение, а харнесс поймал все упрощения агента — пока их было дёшево исправить.
Спек-гейт: самый дешёвый датчик
Минимальный сенсор — скрипт scripts/spec-gate.sh <change-name> [base-ref]. Он падает в двух случаях: diff вышел за пределы списка Allowed files или какой-то критерий не покрыт тестом. Скрипт совместим с bash 3.2 — версией по умолчанию на macOS:
#!/usr/bin/env bash
set -euo pipefail
change="$1"
base="${2:-origin/main}"
spec="specs/active/$change/spec.md"
status=0
allowed=$(sed -n '/^## Allowed files/,/^## /p' "$spec" | grep '^- ' || true)
for file in $(git diff --name-only "$base"...HEAD); do
if ! printf '%s\n' "$allowed" | grep -qx -- "$file"; then
echo "out of scope: $file"
status=1
fi
done
for ac in $(grep -o 'AC-[0-9]*' "$spec" | sort -u); do
if ! grep -rqw "$ac" tests/; then
echo "no test mentions $ac"
status=1
fi
done
exit $status
Деталь, на которой автор делает акцент: проверка критериев использует grep -w — поиск по целому слову. Без него тест, упоминающий AC-10, закрывал бы и AC-1: подстрока AC-1 входит в AC-10.
В CI скрипт подключается одним шагом:
name: spec-gate
on: pull_request
jobs:
gate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- run: scripts/spec-gate.sh "$GITHUB_HEAD_REF" "origin/$GITHUB_BASE_REF"
Имя ветки служит именем папки со спекой, а fetch-depth: 0 даёт полную историю git для сравнения с базовой веткой.
У гейта есть честное ограничение: он доказывает, что агент не вышел за границы и не пропустил ни одного критерия, но не доказывает, что тесты хорошие. Для этого нужны отдельные гейты на тестовые доказательства.
Что происходит без второй половины
Спецификация без харнесса — документ, который никто не проверяет механически. Отклонения от неё всплывают только на дорогом человеческом ревью. Сообщество OpenSpec признаёт: OpenSpec проверяет лишь то, что артефакты существуют.
Харнесс без спецификации — зелёный конвейер, нацеленный не туда. Anthropic описала ловушку так: «Когда агентов просят оценить их собственную работу, они обычно уверенно её хвалят». Лекарство — заранее согласованные критерии. То есть спецификация, как её ни называй.
И оговорка OpenAI: результаты эксперимента нельзя переносить на другие команды без сопоставимых вложений. Харнесс строят, а не устанавливают.
Стартовый харнесс за неделю
С чего начать — примерно неделя работы. Порядок по убыванию отдачи:
- Сделайте AGENTS.md картой: коротко, со ссылками на спеки, архитектурные заметки и команды.
- В каждую спеку добавьте нумерованные критерии приёмки и список разрешённых файлов.
- Подключите спек-гейт к CI: он почти ничего не стоит и ловит больше всего.
- Соберите один настоящий слой тест-харнесса: фикстуры, мок-сервер или поднятие окружения — в зависимости от того, на чём спотыкаются ваши агенты.
- Добавьте в шаблон PR раздел с доказательствами: имена тестов по каждому критерию, логи, скриншоты. Ревьюеру будет что читать.
- Превращайте повторяющиеся ошибки в новые контролы: ошибка повторилась — добавьте гайд (строку в AGENTS.md, шаблон спеки) или сенсор (линтер, тест).
Спецификация говорит агенту, что сделать. Харнесс проверяет, что сделано именно это. По отдельности каждая дисциплина оставляет дыру ровно там, где заканчивается другая.