Один проход — недостаточно: как Signum научился исправлять свой код
Верификация AI-кода как цикл, а не гейт. Итеративный аудит, самокритика контрактов и общий контекст между задачами в Signum v4.6.
Первая версия Signum работала в один проход: CONTRACT → EXECUTE → AUDIT → PACK. Если аудит находил проблему — блок. Человек разбирается.
Это честный процесс, но ограниченный. Представьте код-ревью, где ревьюер может только комментировать, а автор не может ничего исправить. Финдинг уходит обратно в очередь, контекст теряется, цикл начинается заново. Signum v4.6 закрывает этот разрыв: пайплайн теперь зацикливается на трёх уровнях — код, контракт и проектный контекст — прежде чем собрать финальный proofpack.
Проблема: one-shot верификация
В предыдущих постах я разбирал контракт как точку истины и proofpack как артефакт верификации. Архитектура работала: спецификация → ослеплённая реализация → мультимодельный аудит → proof artifact. Но в продакшн-использовании проявился паттерн.
Большинство находок аудита в наших ранних прогонах — не архитектурные проблемы. Это пропущенный edge case в обработке ошибок. Забытый null check. Тест, который не покрывает один из acceptance criteria. Вещи, которые инженер-агент мог бы исправить за секунды — если бы получил шанс.
Вместо этого Signum ставил AUTO_BLOCK, человек смотрел на находку, перезапускал пайплайн. Полная пересборка контракта, полная реализация, полный аудит — для бага, который чинится одной строкой.
Цикл 1: код — итеративный аудит
Signum v4.6 добавляет цикл ремонта, связывающий AUDIT и EXECUTE. Когда аудит находит MAJOR или CRITICAL проблемы, вместо блокировки инженер возвращается чинить:
AUDIT → findings → re-enter EXECUTE (repair) → AUDIT → ... → PACK
После первого прохода аудита (механик + Claude + Codex + Gemini), если есть actionable находки, инженер-агент получает repair_brief.json:
{
"iteration": 1,
"findings": [
{
"id": "F-1",
"severity": "MAJOR",
"file": "src/api/tokens.py",
"line": 42,
"description": "Missing error response when rate limit storage is unavailable",
"source": "codex"
}
]
}
Важно: repair_brief.json содержит только наблюдаемые симптомы дефектов из видимых критериев и детерминированных проверок. Провалы holdout-сценариев описываются как поведенческие наблюдения (“функция возвращает 200 вместо ожидаемого 429”) без раскрытия скрытых критериев приёмки. Data-level blinding из оригинального контракта сохраняется — инженер никогда не видит raw holdout text.
Инженер чинит. Полный аудит перезапускается — не на diff от ремонта, а на всю реализацию от начала. Затем PACK собирает финальный proofpack, как и раньше.
Ключевые решения:
Best-of-N, не last-of-N. Пайплайн хранит артефакты каждой итерации в .signum/iterations/NN/. Если итерация 3 хуже итерации 2 (ремонт сломал что-то другое), Signum откатывается к лучшему кандидату. Не слепая вера в то, что последний ремонт — лучший.
Diff progression. На первом проходе ревьюеры видят полный патч. На проходе 2+ — полный патч плюс дельту итерации с инструкцией фокусироваться на том, что изменилось в ремонте. Это экономит токены и снижает шум. Если дельта >80% от полного патча — fallback на полный diff (ремонт слишком большой, чтобы рассматривать инкрементально).
Early stop. Если две итерации подряд не улучшают результат — остановка. Максимум 20 итераций (настраивается через SIGNUM_AUDIT_MAX_ITERATIONS). На практике сходимость за 2-3 прохода.
Finding fingerprints. Каждая находка получает отпечаток на основе файла, диапазона строк и типа проблемы. Между итерациями Signum классифицирует каждый финдинг как resolved, persisting или new. Синтезатор использует это для оценки реального прогресса — не просто “меньше находок”, а “какие конкретно проблемы исправлены и какие появились”.
Фильтрация галлюцинаций. Если ревьюер ссылается на строку, которой нет в diff, или на файл вне scope — находка отбрасывается. Это тот же механизм, что описан в посте об экосистеме: каждый AI-финдинг валидируется против реального diff перед попаданием в repair loop.
Цикл 2: контракт — самокритика
Цикл кода чинит реализацию. Но что если проблема выше — в самом контракте? Идеальная реализация ошибочной спецификации — всё ещё провал.
Для задач среднего и высокого риска контрактор теперь запускает 4-проходную самокритику перед тем, как показать контракт человеку:
- Ambiguity review — сканирует goal, acceptance criteria и scope на неоднозначные формулировки
- Missing-input review — проверяет недостающие предусловия, записывает решения по уточнениям
- Contradiction review — ищет противоречия между целью, scope и уровнем риска
- Coverage review — реконструирует цель из критериев приёмки, проверяет покрытие, документирует происхождение допущений
Максимум 2 раунда авторевизии. Если после второго раунда вердикт "no-go" — эскалация к человеку. Задачи низкого риска пропускают все 4 прохода.
Результат записывается в контракт:
{
"readinessForPlanning": {
"verdict": "go",
"summary": "All ambiguities resolved. AC3 coverage gap closed in round 1."
},
"ambiguityCandidates": [...],
"contradictionsFound": [],
"clarificationDecisions": [...]
}
Человек видит и вердикт, и весь путь к нему. Не “контрактор решил, что контракт хороший” — а какие проблемы были найдены и как устранены.
Цикл 3: проект — общий контекст между контрактами
Цикл кода итерирует внутри одной задачи. Цикл контракта итерирует внутри одной спецификации. Но предыдущие версии Signum работали с контрактами изолированно. Каждая задача — отдельная вселенная. В реальном проекте задачи связаны: трогают одни файлы, зависят от одних решений, используют одну терминологию.
Три новых слоя:
Project intent. Файл project.intent.md в корне проекта — цель, возможности, non-goals, персоны. Контрактор читает его перед генерацией контракта. Non-goals проекта становятся ограничениями scope контракта. Для средне- и высокорискованных задач отсутствие intent — блокирующий вопрос.
Glossary. project.glossary.json определяет канонические термины и запрещённые синонимы. glossary_check сканирует контракт на использование алиасов, terminology_consistency_check ловит расползание синонимов между активными контрактами. Оба — WARN, не блок.
Cross-contract coherence. overlap_check находит пересечения inScope между активными контрактами (два контракта трогают один файл — конфликт?). assumption_check ищет противоречия в допущениях между связанными контрактами. adr_check предупреждает, когда релевантные ADR существуют, но не упоминаются в контракте.
Плюс upstream staleness detection: контрактор хэширует содержимое project.intent.md и глоссария при создании контракта. Если upstream-файлы изменились к моменту выполнения — предупреждение (или блок, если настроено stalenessPolicy: "block").
Архитектура v4.6.1: checks как отдельные скрипты
Бонус последнего рефакторинга: 6 inline-проверок, которые жили внутри оркестратора, вынесены в отдельные testable-скрипты в lib/:
lib/glossary-check.sh — сканирование запрещённых синонимов
lib/terminology-check.sh — расползание терминов между контрактами
lib/overlap-check.sh — пересечение inScope
lib/assumption-check.sh — противоречия в допущениях
lib/adr-check.sh — проверка релевантных ADR
lib/staleness-check.sh — устаревание upstream-артефактов
Все скрипты: JSON stdout, stderr для диагностики, exit 0 для любого результата проверки (non-zero только для инфраструктурных ошибок). Оркестратор вызывает скрипты и сам решает, блокировать или предупредить. Разделение ответственности: скрипт проверяет, оркестратор решает.
Что это меняет
Signum v3 отвечал на вопрос “корректно ли это?” одним да/нет. v4.6 отвечает на вопрос “можно ли это сделать корректным?” — и если да, делает.
В наших ранних прогонах заметная доля задач, которые v3 блокировал с AUTO_BLOCK, v4.6 доводит до AUTO_OK за 2-3 итерации без участия человека. Задачи, которые всё ещё блокируются — как правило реальные проблемы спецификации или архитектуры, то есть именно то, что и должно эскалироваться к человеку.
Верификация — не гейт в конце пайплайна. Это цикл. Тот же принцип, что и в человеческом код-ревью: находка → исправление → перепроверка. Разница в том, что AI может пройти этот цикл за секунды, а не за дни.
Ссылки
- signum на GitHub
- Контракт — это контекст — первый пост серии
- AI пишет код. Где доказательства? — второй пост серии
- skill7.dev/development/signum
- emporium — маркетплейс плагинов