Контракт — это контекст: как Signum делает верификацию AI-кода принципиальной
Почему прогнать AI-код через ещё больше AI-ревьюеров не решает проблему надёжности — и что меняет подход contract-first.
Можно прогнать AI-diff через три модели и всё равно не иметь точки истины. Они скажут что выглядит “разумно”, а не что корректно.
Модель отказа не в “плохом коде”. Она в нефальсифицируемом намерении: требование так и не стало чем-то, что можно запустить. Вы одобрили реализацию, удовлетворяющую вашим допущениям. Граничные случаи, которые вы не потрудились специфицировать, не были пойманы — потому что ловить было не против чего. Два месяца спустя приходит баг-репорт.
Это проблема контекстной инженерии.
Недостающий слой контекста
У каждого процесса верификации нужно две вещи: артефакт, который проверяется, и стандарт, относительно которого он проверяется. Современное код-ревью сильно с первым и слабо со вторым. “Стандарт” живёт в голове ревьюера — восстановленный из описания задачи, комментариев и окружающего кода. Неявный, неполный, ни с кем не разделённый.
Контекстная инженерия — это превращение неявного контекста в явный. Для верификации это означает: стандарт должен существовать до начала реализации, а не после. Контракт — это контекст. Без него всякое ревью — это интерпретация.
Signum: контракт как точка истины
Signum — плагин для Claude Code, реализующий четырёхфазный пайплайн:
CONTRACT → EXECUTE → AUDIT → PACK
CONTRACT идёт первым. Вы описываете задачу на естественном языке. Агент-контрактор (Claude Sonnet) формализует её в contract.json:
{
"goal": "Добавить rate limiting на POST /api/tokens — макс. 5 запросов в минуту на IP",
"acceptanceCriteria": [
{
"id": "AC1",
"description": "Запросы сверх лимита возвращают 429 с заголовком Retry-After",
"verify": "pytest tests/test_rate_limit.py -k test_429_response",
"holdout": false
},
{
"id": "AC2",
"description": "Счётчик rate limit сбрасывается после истечения окна",
"verify": "pytest tests/test_rate_limit.py -k test_window_reset",
"holdout": true
}
],
"inScope": ["src/api/tokens.py", "tests/test_rate_limit.py"],
"riskLevel": "medium"
}
Спецификация оценивается по шкале A–F по шести измерениям (тестируемость, покрытие негативных сценариев, ясность, область, полнота, граничные случаи). Оценка D — жёсткая остановка: пайплайн не продолжается, пока спецификация не станет верифицируемой.
EXECUTE: Агент-инженер получает contract-engineer.json — контракт с физически удалёнными критериями holdout: true. Он реализует против видимой спецификации. Оптимизировать под то, чего не видишь, невозможно.
AUDIT: Механик (детерминированный, без LLM) запускает lint, typecheck и тесты относительно pre-реализационного baseline. Затем Claude, Codex и Gemini независимо проверяют diff параллельно. Holdout-критерии — AC2 в примере выше — запускаются против готового результата. Если инженер забыл сбросить счётчик после истечения окна, это поймается здесь, автоматически, против критерия, который он никогда не видел.
PACK: proofpack.json — SHA-256 контракта, временная метка одобрения, базовый коммит, diff, результаты аудита. CI строит гейты на нём.
Что блокирует Signum
До начала реализации Signum отклоняет:
- Критерии приёмки без команды
verify(нельзя проверить = не критерий) - Размытую область (“измени auth-модуль” без конкретных файлов)
- Рискованные допущения, выявленные внешними валидаторами (Codex + Gemini проверяют спецификацию на пробелы)
- Спецификации с оценкой ниже D — недостаточные граничные случаи, покрытие негативных сценариев, ясность
После реализации AUTO_BLOCK при:
- Нарушениях политики (слишком много изменённых файлов, запрещённые bash-паттерны в diff)
- Регрессиях инвариантов репозитория (если
pytest -qпроходил до — должен проходить после) - Провале holdout-сценариев
Инварианты на уровне репозитория: постоянный контракт
Контракты уровня задачи покрывают то, что вы строите сейчас. repo-contract.json — то, что должно выполняться всегда:
{
"invariants": [
{ "id": "I-1", "description": "All tests pass", "verify": "pytest -q", "severity": "critical" },
{ "id": "I-2", "description": "No type errors", "verify": "mypy src/", "severity": "critical" }
],
"owner": "human"
}
Signum фиксирует baseline до EXECUTE, перезапускает после. Любая регрессия — AUTO_BLOCK, вне зависимости от результатов уровня задачи. Поле "owner": "human" объявляет этот файл человеческим артефактом. AI enforces; человек определяет.
Цепочка аудита
При одобрении пользователем Signum хэширует contract.json (SHA-256) и фиксирует временную метку. До запуска инженера записывается базовый коммит. Итоговый proofpack связывает: одобренный контракт → базовый коммит → diff реализации → результаты аудита. Нельзя задним числом заменить контракт и заявить, что proofpack был построен против него.
Это важно по мере того, как AI-сгенерированный код всё чаще требует провенанса. Не “AI написал это” — “AI реализовал это против этого контракта, валидированного до реализации, с этими результатами аудита.”
Установка
# Добавить маркетплейс (один раз)
claude plugin marketplace add heurema/emporium
# Установить Signum
claude plugin install signum@emporium
# Опционально: внешние CLI для мультимодельного аудита
# https://github.com/openai/codex
# https://github.com/google-gemini/gemini-cli
Затем:
/signum "добавить rate limiting на API endpoint"
Signum оценивает спецификацию, показывает контракт на одобрение, запускает инженера с удалёнными holdouts, проводит аудит с нескольких сторон и создаёт proofpack.json.
Статус
Работает сейчас: четырёхфазный пайплайн, гейт качества спецификации, holdout-сценарии, инварианты репозитория, цепочка аудита, proofpack.
Требует: Claude Code v2.1+, git, jq, python3. Мультимодельный аудит дополнительно требует Codex CLI и Gemini CLI — Signum деградирует корректно при отсутствии любого из них.
В процессе изменений: схемы артефактов (proofpack, contract) будут меняться. Суждение контрактора о качестве holdout улучшается с использованием.
Мы запускаем Signum на собственной разработке Signum. v3 — первая версия, на которую мы готовы ставить в своих проектах.
Обратная связь
Signum молодой и активно разрабатывается. Если он блокирует некорректно, упускает граничный случай или оценка спецификации кажется неправильной — можно сообщить прямо из Claude Code, без переключения контекста.
Установите Reporter:
claude plugin install reporter@emporium
Затем: /report bug или /report feature или /report question
Reporter автоматически определяет, что вы работаете с продуктом heurema, прикрепляет контекст среды (ОС, оболочка, версия Claude Code), показывает предпросмотр перед отправкой и падает обратно на буфер обмена, если gh недоступен.