Clean Architecture для AI-агентов: как проектировать инженерный harness. AI Agnet.. AI Agnet. harness.. AI Agnet. harness. llm.. AI Agnet. harness. llm. искусственный интеллект.. AI Agnet. harness. llm. искусственный интеллект. Ненормальное программирование.

Работа с coding-агентом часто начинается с простой схемы: разработчик формулирует задачу, передаёт репозиторий и просит подготовить изменение. Агент читает код, редактирует несколько файлов, запускает тесты и возвращает результат.

В продуктовом репозитории этой схемы быстро становится недостаточно. Агенту нужно определить границы изменения: какой компонент владеет поведением, какие сценарии от него зависят, какие ограничения нельзя нарушать и где находятся потребители изменяемого контракта. После реализации кто-то должен установить, соответствует ли результат исходному намерению, достаточно ли проведённых проверок и относятся ли они к текущей версии кода.

Генерация кода становится всё доступнее. Основная сложность смещается к организации среды, в которой агент систематически готовит корректные изменения.

Что такое harness

В статье Harness engineering OpenAI использует это понятие для описания инженерной среды вокруг coding-агентов. На качество результата влияют структура репозитория, доступный контекст, инструменты, правила работы и скорость обратной связи.

В этой статье под harness я буду понимать репозиторно-локальную инженерную систему, которая превращает человеческое намерение в ограниченное, воспроизводимое и проверенное изменение продукта.

У такой системы есть три связанные части.

Оркестрационный слой управляет процессом: фиксирует задачу и полномочия участников, проводит работу через исследование, проектирование, реализацию, проверку и интеграцию. Существенны не названия стадий, а явные условия перехода между ними.

Семантический слой предоставляет модель продукта. Списка файлов для этого недостаточно. Агенту полезно понимать владельцев поведения, границы компонентов, пользовательские маршруты, состояние, инварианты и связи между потребителями.

Validation-слой устанавливает, к какой версии кода относятся результаты проверок, соответствует ли их набор масштабу изменения и сохранили ли собранные evidence актуальность. Независимый reviewer оценивает смысл результата и ищет расхождения между контрактом и реализацией.

Допустим, агенту поручено изменить пользовательский сценарий desktop-приложения. Найти обработчик события — начальная часть задачи. Ещё нужно обнаружить владельца состояния, проверить соседние маршруты, найти потребителей контракта и сохранить режимы восстановления после сбоя. Семантическая модель помогает построить область изменения, контракт фиксирует ожидаемое поведение, а validation связывает наблюдения с конкретным кандидатом.

Каждый элемент можно реализовать в Markdown, JSON, коде, базе данных, CLI или CI. Форматы вторичны. Важные знания и решения должны существовать за пределами промпта, истории чата и памяти отдельного разработчика.

Главная задача harness — сократить объём человеческого внимания, необходимого для получения надёжного изменения, и сохранить управляемость системы. Максимальная автономность агента сама по себе такой цели не гарантирует.

При чём здесь Clean Architecture

Роберт Мартин писал Clean Architecture для мира, в котором программные системы в основном создавали «белковые» инженеры. Команды выбирали фреймворки, подключали базы данных, развивали бизнес-логику и постепенно обнаруживали, что каждое следующее изменение обходится дороже предыдущего.

Главная тема книги — сохранение изменяемости программной системы. В первых двух главах Мартин разделяет две ценности ПО: поведение и архитектуру. Система должна выполнять текущие требования и оставаться пластичной для требований будущих. Поведение обычно выглядит срочным. Архитектура редко требует немедленного внимания, поэтому ею легко пожертвовать.

Coding-агенты резко увеличивают скорость производства поведения. За короткое время они способны изменить десятки файлов, добавить тесты и обновить документацию. Однако скорость генерации не сохраняет архитектуру автоматически. Агент может быстрее человека размножать связанность, копировать неудачные паттерны и добавлять локально правдоподобные решения, которые повышают стоимость следующих изменений.

Отсюда особая актуальность формулировки из главы 1: цель архитектуры — минимизировать человеческие затраты на создание и сопровождение системы в течение её жизненного цикла. Стоимость генерации снижается, но постановка задачи, восстановление контекста, проверка и исправление результата по-прежнему требуют времени.

Теперь собственная архитектура нужна и harness. У него есть предметная область — управляемое изменение продукта; use cases — research, design, implementation, assurance, review и integration; high-level policy — authority, contracts, permissions, evidence validity и verdicts; внешние механизмы — модели, Git, CI, хранилища и пользовательские интерфейсы.

Следовательно, принципы книги можно применить уровнем выше: проектировать нужно и продукт, и систему, которая его изменяет.

Главная метрика: стоимость надёжного изменения

Эффективность harness легко измерять временем запуска, стоимостью токенов, размером diff или долей тестов, прошедших с первой попытки. Эти показатели полезны для эксплуатации, но не показывают, сколько работы осталось человеку.

Представим два запуска одного задания. Первый агент заканчивает работу за пятнадцать минут и сообщает, что тесты проходят. Инженеру затем приходится выяснять, какие команды запускались, к какой версии кода относится результат, все ли сценарии проверены и соответствует ли реализация намерению.

Второй запуск занимает двадцать пять минут. Вместе с изменением агент оставляет привязку к задаче, точную версию кандидата, перечень проверок, описание затронутых частей продукта и независимый review verdict.

По скорости агента выигрывает первый запуск. По стоимости получения надёжного изменения — второй. Результатом работы harness служит кандидат, для которого можно обоснованно принять решение об интеграции.

В главе 1 Мартин предлагает оценивать архитектуру по усилиям, необходимым для создания и сопровождения системы. Для harness полная стоимость складывается из постановки задачи, восстановления контекста, выполнения, проверки, исправлений, восстановления после сбоев и влияния на будущую работу.

Последняя часть часто выпадает из измерений. Новая проверка может зависеть от внутреннего формата конкретного раннера. Текущая задача завершится успешно, но следующая замена раннера потребует изменить саму проверку, формат evidence и правила readiness. Часть стоимости просто перенесена в будущее.

Во второй главе книги это различие раскрывается через масштаб и форму изменения. Масштаб описывает объём нового поведения. Форма определяет, насколько удобно оно укладывается в существующую архитектуру. Две задачи сопоставимого масштаба могут иметь разную стоимость, если одна локальна, а другая проходит через несколько случайно связанных подсистем.

Тот же эффект возникает внутри harness. Добавление одного обязательного check выглядит небольшой задачей. В плохо организованной системе ради него приходится одновременно редактировать инструкции агента, оркестратор, CI, формат отчёта, parser и документацию ролей. Стоимость выросла из-за формы системы.

Глава 15 описывает основные расходы сопровождения как исследование существующей системы и риск случайной поломки. Семантический слой сокращает исследование: помогает найти владельцев, маршруты и потребителей. Assurance сокращает риск: фиксирует candidate identity, выполненные проверки, найденные отклонения и срок применимости результатов.

Фраза «тесты прошли» почти бесполезна, пока неизвестны состав тестов, команда запуска, базовая версия и проверяемый commit. Без этих сведений инженер вынужден повторять работу самостоятельно.

Локальная экономия тоже может увеличивать итоговую стоимость. Один агент способен сразу реализовать задачу и одобрить собственный результат. Запуск станет короче, но ошибочное предположение пройдёт через обе стадии. Повторный цикл исследования, исправления и review съест выигрыш.

Пропускная способность отдельной стадии также мало говорит о производительности системы. Если агенты ежедневно создают двадцать изменений, а инженеры успевают надёжно проверить три, система выпускает три изменения. Остальные образуют очередь и постепенно устаревают: меняется base revision, расходятся контракты, теряют актуальность результаты тестов.

Поэтому архитектурные решения нужно оценивать по полному циклу. Разделение ролей полезно, если снижает количество пропущенных ошибок и стоимость review. Семантическая модель оправдана, если сокращает поиск и риск. Строгий evidence contract нужен, если избавляет человека от ручной реконструкции запуска. Новая граница имеет смысл, если удерживает будущие изменения локальными.

Главная метрика harness — совокупная стоимость надёжного изменения на протяжении жизненного цикла системы.

Policy и details: что именно нужно защищать

У harness есть собственные бизнес-правила: кто определяет намерение, какие решения фиксирует проектировщик, где заканчиваются полномочия исполнителя, какие evidence необходимы для приёмки и кто выносит итоговый verdict.

Рядом находятся механизмы исполнения: LLM-провайдеры, Git, CLI, CI, файловая система, форматы сериализации и тестовые раннеры. Граница проходит не между кодом и конфигурацией, а между причинами изменения. Policy меняется вслед за инженерными правилами процесса. Detail меняется вслед за моделью, протоколом, хранилищем или инструментом.

Глава 19 предлагает разделять политики по уровню и причине изменения. Чем дальше правило находится от ввода и вывода, тем выше его уровень. Для harness это даёт три слоя:

authority · lifecycle · permissions · evidence validity · verdicts
research · design · implementation · assurance · review · integration
models · prompts · Git · CI · test runners · storage · UI

Это схема зависимостей, а не обязательная структура процессов или каталогов. Небольшой harness может исполнять все уровни в одном приложении.

Во время работы high-level use case обращается к внешнему механизму: запускает модель, тестовый раннер или Git-команду. Зависимость в коде полезно направить обратно. Use case определяет нужный контракт, а внешний adapter его реализует. Поток управления и направление зависимостей в таком случае различаются — именно этот приём Мартин разбирает в главах 19 и 22.

Например, assurance запрашивает run_check(check_id, candidate) и получает нормализованный check_observation. Для него несущественно, выполнена ли проверка локально, в CI или удалённым сервисом. Adapter преобразует вывод pytest, JUnit XML или другого раннера во внутренний формат. Readiness policy не знает деталей инструмента.

LLM занимает такое же внешнее положение. У моделей различаются API, tool calls, размеры контекста, схемы структурированного ответа и поведение при ошибках. Эти свойства меняются быстрее, чем смысл ролей.

Reviewer обязан сопоставить реализацию с контрактом, оценить evidence и вернуть один из допустимых verdicts. Это policy роли. System prompt, provider schema и стратегия повторного запроса относятся к adapter исполнения. Если правила reviewer существуют только внутри большого промпта, замена модели превращается в повторное проектирование роли.

Глава 21 называет ещё один критерий — Screaming Architecture. Верхний уровень репозитория должен сообщать о назначении системы. Структура из prompts, scripts, models и tools показывает механизмы. Структура вокруг task-intake, design, implementation, assurance, review и integration показывает жизненный цикл изменения.

Название каталога не создаёт границу. Если review импортирует типы конкретного LLM SDK и анализирует сырой ответ провайдера, механизм всё ещё управляет use case. Направление зависимостей должно подтверждать структуру.

Практический тест границы состоит в замене детали. Сохранится ли review contract после смены модели? Можно ли перенести evidence в другое хранилище без изменения правил актуальности? Сможет ли lifecycle работать через локальный CLI и CI? Хорошая граница не обещает бесплатной замены, но ограничивает область изменений adapter и явно обозначенной частью use case.

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

Роли как границы ответственности и полномочий

Первую версию harness часто строят вокруг универсального агента. Он исследует задачу, выбирает решение, меняет код, запускает проверки и оценивает собственный результат. Процесс компактен, но соединяет решения разной природы. Факты о текущем продукте смешиваются с намерением изменения, исполнитель уточняет контракт под написанный код, а проверка опирается на предположения реализации.

Проблема связана не с количеством действий, а с несколькими источниками требований к одной роли.

В главе 7 Мартин уточняет смысл Single Responsibility Principle: модуль должен отвечать перед одним actor — группой, которая служит причиной его изменения. Для harness этот принцип можно перенести на источники полномочий и критерии правильности.

Исследователь отвечает за точность наблюдений о текущей системе. Проектировщик — за полноту предлагаемого механизма. Исполнитель — за соответствие реализации принятому контракту. Reviewer — за поиск расхождений и достаточность evidence. Координатор сохраняет связь с человеческим намерением и принимает решения, которые нельзя вывести из репозитория механически.

Эти роли меняются по разным причинам. Новое правило review не должно влиять на поведение implementer. Дополнительная инструкция исследователю не должна расходовать контекст во время реализации. Формат design contract не должен раскрывать каждой стадии внутренние детали проектирования.

Роль определяется правом на решение

Список действий плохо определяет роль. Два агента могут читать одинаковые файлы и запускать одинаковые команды, но обладать разными полномочиями.

Исследователь устанавливает текущее поведение, но не превращает его в продуктовое требование. Проектировщик фиксирует механизм, но не подтверждает качество будущей реализации. Исполнитель изменяет код в рамках контракта и не расширяет scope самостоятельно. Reviewer выносит verdict по кандидату, но не переписывает его во время той же проверки.

Поэтому role contract должен задавать входные данные, разрешённые утверждения, доступное для изменения состояние и запрещённые решения. Последняя часть особенно важна: разделение работает за счёт ограничений, а не за счёт разных названий агентов.

Технически роли может исполнять одна модель. Граница сохраняется при отдельных контекстах, разных контрактах, ограниченных инструментах и несовместимых полномочиях. Несколько моделей тоже не гарантируют архитектуру: при общем состоянии и общей власти они образуют одну распределённую роль.

Multi-agent architecture определяется разделением authority, а не количеством работающих LLM.

Независимое review разрывает цикл самооценки

Исполнитель располагает подробным контекстом собственных решений. Этот контекст помогает писать код, но мешает заново проверить исходные предположения. Агент уже выбрал интерпретацию задачи и объяснил себе, почему решение корректно.

Независимый reviewer начинает с другой позиции. Для него реализация является недоверенным кандидатом. Основанием служат принятый контракт, наблюдаемый diff и воспроизводимые evidence. Объяснение исполнителя может дать подсказку, но не заменяет проверку.

Независимость создаётся устройством процесса: контракт фиксируется заранее, reviewer получает свежий контекст, verdict ссылается на наблюдения, а изменение кандидата требует новой проверки его актуальности. Reviewer не должен исправлять код и сразу одобрять новую версию.

Модель reviewer может совпадать с моделью исполнителя. Важнее отдельная сессия и отсутствие права на самоодобрение.

Каждой роли нужен собственный интерфейс

После разделения ролей возникает соблазн передавать каждой полный task record, всю семантическую модель, историю решений и логи исполнения. Формально агент получает максимум информации. Фактически растут стоимость контекста и зависимость от посторонних деталей.

Interface Segregation Principle из главы 10 требует, чтобы потребитель не зависел от данных и операций, которыми не пользуется. В harness интерфейсом роли служит её контекст.

Исследователю нужны вопрос, границы поиска и доступные источники. Исполнителю — принятый контракт, релевантный срез продукта, ограничения рабочей области и команды проверок. Reviewer получает контракт, кандидат, evidence и критерии verdict.

Остальная информация остаётся доступной через явные ссылки и дополнительные запросы. Такой progressive disclosure сохраняет компактный начальный контекст без искусственного запрета на исследование.

Изменение review receipt тогда не затрагивает researcher. Расширение семантической модели UI-маршрутов не увеличивает контекст исполнителя серверной задачи. Независимые причины изменения получают независимые projections.

Liskov Substitution Principle из главы 9 добавляет требование к реализации роли. Совпадающей JSON-схемы недостаточно. Две модели взаимозаменяемы только при соблюдении наблюдаемого контракта: допустимых verdicts, обязательных ссылок на evidence, правил отказа, ограничений полномочий и условий завершения. Иначе оркестратор начинает накапливать специальные случаи для отдельных провайдеров.

Open-Closed Principle из главы 8 полезен при расширении набора ролей. Новый security reviewer должен добавляться через контракт, реализацию, eval-набор и регистрацию. Если ради него приходится менять ядро authority и существующие роли, точка расширения выбрана неудачно. Полноценная plugin-система при этом не обязательна: простой registry и устойчивый интерфейс часто решают задачу.

Разделять роли следует по реальным осям изменения. Две функции можно оставить вместе, если они отвечают перед одним источником требований и используют одинаковые критерии правильности. Новая граница оправдана при различии полномочий, конфликте интересов, отдельной модели риска или самостоятельном темпе развития.

Семантический слой: модель продукта поверх файлов

Репозиторий уже содержит подробное описание продукта. Код показывает реализованное поведение, схемы задают форматы данных, тесты фиксируют часть ожиданий. Однако эти сведения организованы для исполнения программы. Агенту приходится восстанавливать продуктовую картину: где начинается сценарий, какой компонент владеет состоянием, кто потребляет контракт и какое поведение считается инвариантом.

Обычный поиск отвечает на вопрос «где встречается это имя». Архитектурная задача чаще требует другого ответа: «какие части системы участвуют в этом поведении и почему изменение одной части затрагивает остальные».

Семантический слой хранит связь между устройством продукта и его реализацией. Он представляет кодовую базу через архитектурно значимые понятия:

  • product areas и владельцев поведения;

  • пользовательские и системные маршруты;

  • границы компонентов;

  • состояние и переходы;

  • инварианты, отказы и восстановление;

  • потребителей контрактов;

  • ссылки на код и схемы, где утверждения можно проверить.

Это модель продукта, а не копия содержимого репозитория.

Модель важнее способа хранения

В главе 30 Мартин различает модель данных и базу данных. Структура данных архитектурно значима. База служит механизмом хранения и доступа.

Для семантического слоя действует тот же принцип. Значение имеют owner, route, boundary, state, invariant и отношения между ними. Хранить их можно в Markdown, JSON, реляционных таблицах, графе или поисковом индексе.

Небольшому репозиторию может хватить нескольких версионируемых файлов. Граф упростит обход сложных связей. Embeddings помогут найти близкие по смыслу фрагменты. Ни один механизм сам не устанавливает владение поведением, направление зависимости или продуктовый инвариант.

Сначала определяются понятия и запросы к ним. Затем выбирается хранилище.

Глава 20 разделяет устойчивые сущности и прикладные use cases. Семантическую модель можно строить сходным образом. На верхнем уровне находятся понятия, которые сохраняют смысл при перестройке файлов: пользовательская сессия, документ, разрешение или фоновая операция. Ниже располагаются маршруты, через которые продукт реализует их поведение.

Допустим, пользовательское действие запускает фоновую операцию. UI отправляет команду, прикладной слой создаёт состояние, worker выполняет работу, а отдельный механизм восстанавливает незавершённую операцию после перезапуска. Поиск по имени команды приведёт к UI-обработчику и функции запуска. Семантический маршрут дополнительно покажет владельца состояния, восстановление после сбоя и потребителей результата.

Карта направляет проверку, но не подтверждает сама себя

Любая карта упрощает территорию и способна устареть. Поэтому в harness полезно различать три вида знания:

  • текущее поведение подтверждается кодом, схемами и исполняемыми проверками;

  • намерение изменения определяется принятой задачей и design contract;

  • семантическая модель связывает продуктовые понятия с местами проверки.

Запись «компонент A владеет состоянием операции» полезна при наличии anchors: определения состояния, места его изменения и маршрута восстановления. Агент получает гипотезу и точки проверки. Противоречие с кодом нужно зафиксировать, а не скрывать ради целостности документации.

Такой подход отделяет семантический слой от обычного архитектурного текста. Его ценность определяется пригодностью для навигации и проверки.

Контекст строится под конкретную задачу

Большой репозиторий содержит сотни маршрутов, компонентов и потребителей. Загружать полный граф в каждую роль дорого и бесполезно. Harness должен строить task-scoped projection от product area, маршрута, компонента или инварианта. В проекцию входят ближайшие владельцы, зависимости, потребители и anchors.

Для изменения авторизации начальный контекст может содержать целевой маршрут, границы доверия, владельца сессии, потребителей результата, failure policy и ссылки на реализации. Несвязанные экраны и фоновые процессы останутся за его пределами, но будут доступны по запросу.

Роли получают разные проекции одной модели. Researcher может запросить широкий граф связей. Implementer получает точный контракт и локальные anchors. Reviewer дополнительно видит затронутые инварианты и ожидаемые проверки.

Актуальность входит в lifecycle

Семантический слой устаревает, если его обновление остаётся необязательной работой после реализации. Каждое значимое утверждение полезно связать с областью действия, code anchors, проверенной версией и владельцем актуализации.

Изменение anchor или связанного контракта создаёт obligation: подтвердить утверждение, обновить его или пометить устаревшим. Такой сигнал не утверждает, что смысл обязательно изменился. Он лишь отзывает прежнюю гарантию актуальности.

Автоматика способна обнаружить удалённый файл, переименованный символ или несовпадение версии. Смысловое соответствие часто требует агента или человека. Harness отделяет механическое обнаружение повода от содержательного решения.

Семантический слой оправдан, если сокращает поиск владельца поведения, помогает заранее найти consumers и улучшает оценку impact. Он должен моделировать устойчивые понятия продукта, предоставлять проверяемые anchors и выдавать ролям компактные проекции под задачу.

Validation и assurance: от проверки к решению

Фраза «все тесты прошли» служит одним наблюдением о кандидате. Тест может относиться к другой версии кода, не покрывать изменённое поведение или скрывать неподходящую конфигурацию. Даже корректный запуск отвечает только на заложенный в него вопрос.

В главе 4 Clean Architecture тестирование связывается с фальсифицируемостью. Тест способен обнаружить ошибку, но не доказать отсутствие всех ошибок. После серьёзных попыток опровергнуть корректность систему признают пригодной для конкретной цели.

Harness поэтому не должен изображать математическое доказательство. Его задача — организовать попытки опровержения и сохранить результаты в форме, пригодной для воспроизведения и независимой оценки.

Validation и assurance выполняют разную работу

Validation устанавливает механические факты: существует ли задача, совпадает ли кандидат с указанной версией, заполнен ли контракт, выполнены ли обязательные checks, относятся ли evidence к текущему коду и появились ли новые ошибки относительно base revision.

Assurance отвечает на более широкий вопрос: достаточно ли наблюдений для инженерного решения. Здесь оцениваются соответствие намерению, полнота проверки, архитектурные последствия, риск пропущенных consumers и failure scenarios.

Механический validator может подтвердить наличие review verdict и его связь с кандидатом. Из этого факта нельзя вывести, что reviewer правильно понял продукт. Смешение уровней создаёт ложную уверенность: зелёная панель может подтверждать корректность формата и успешный запуск нескольких команд, но не смысл изменения.

Candidate, evidence и verdict образуют цепочку происхождения

Evidence имеет смысл относительно точного объекта проверки. Имя Git-ветки для этого не подходит: оно указывает на разные commits в разное время. Рабочее дерево добавляет незакоммиченные изменения, которые могли участвовать в запуске и отсутствовать в сохранённой версии.

Candidate identity должна фиксировать authority задачи, base revision, candidate revision, состояние рабочего дерева и область diff. Все evidence и verdicts ссылаются на эту идентичность.

Такое правило обнаруживает частую ошибку: агент запускает тесты, затем исправляет файл и передаёт старый отчёт вместе с новым кодом. Проверка действительно была зелёной, но относилась к предыдущему кандидату.

Запись tests_passed: true тоже недостаточна. Полезная единица evidence содержит candidate ID, check ID и версию определения, способ запуска, существенные параметры окружения, время, структурированное наблюдение и ссылку либо digest исходного артефакта.

Наблюдение нужно отделять от решения. 127 tests passed описывает результат запуска. Кандидат готов к интеграции — verdict, который опирается на набор наблюдений и policy. После появления нового обязательного security check старые результаты остаются исторически верными, но прежний verdict больше не удовлетворяет текущим правилам.

Глава 6 объясняет архитектурную пользу immutability. Для harness завершённые authority, evidence и verdicts удобно хранить как неизменяемые записи:

authority → design → candidate A → evidence A → verdict A
                       candidate B → evidence B → verdict B

После исправления появляется candidate B и новая ветвь. Verdict A остаётся корректной исторической записью, но не разрешает интеграцию B.

Изменяемое runtime-состояние всё равно необходимо: оркестратор отслеживает активный запуск, очередь и временные ошибки. Его следует отделить от записей решений. Потеря runtime может потребовать повторного запуска. Незаметное изменение evidence разрушает основание для доверия.

Freshness вычисляется по входам решения

Evidence устаревает после изменения candidate revision, контракта задачи, определения обязательного check, base revision или semantic impact. Для внешних наблюдений может действовать временной срок.

Проверка freshness сравнивает текущие входы решения с входами, зафиксированными при создании evidence. Совпадение подтверждает применимость. Расхождение требует повторной проверки или явного исключения с подходящей authority.

Флаг valid: true сообщает прошлое решение, но не объясняет, сохранились ли его основания. Направленный граф происхождения даёт более точную модель:

intent → authority → design → candidate → evidence → review → readiness

Каждый узел ссылается на свои входы. Их изменение не переписывает историю, а отзывает применимость зависимых результатов. Такая модель препятствует циклической authority: кандидат не подтверждает собственный design, evidence не определяет набор проверок для самого себя, reviewer не изменяет код внутри одобряемого verdict.

Внешние инструменты остаются тонкими adapters

Запуск модели, shell-команды, CI и сетевые сервисы зависят от окружения и форматов внешних систем. Глава 23 описывает Humble Object pattern: труднопроверяемое поведение выносится в простой пограничный компонент, а содержательная логика остаётся в детерминированной части.

Adapter CI получает статус job, ссылки на артефакты и логи. Внутренняя policy определяет, относится ли job к нужному commit, входит ли проверка в обязательный набор и разрешает ли результат переход к review.

Проверку candidate identity, schema evidence, freshness, обязательных checks, новых ошибок и integration readiness можно тестировать на фиксированных входных данных. Смена CI или раннера тогда не меняет правила решения.

Тесты сами входят в архитектуру

Глава 28 рассматривает тесты как компонент системы. При сильной связи с внутренней структурой они становятся хрупкими: локальный рефакторинг ломает множество проверок без изменения наблюдаемого поведения.

Для agentic development проблема имеет два уровня. Harness запускает тесты продукта и нуждается в собственных тестах lifecycle, authority, evidence и adapters.

Продуктовые проверки полезно направлять через устойчивые interfaces и testing API. Проверка бизнес-правила через длинный UI-маршрут зависит от разметки, навигации, авторизации и окружения. Узкий testing API проверяет правило ближе к его владельцу.

Тесты harness должны описывать сценарии его предметной области: evidence относится к прежнему candidate; обязательный check отсутствует; verdict не имеет нужной authority; после изменения контракта readiness отозван. Такие тесты выдерживают замену файлового формата или CLI. Проверки точного текста логов и внутренней последовательности функций связывают систему с текущей реализацией.

Автоматика проверяет основания, reviewer оценивает смысл

Validation хорошо работает при однозначном контракте: digest, обязательное поле, допустимый переход, полнота receipts и соответствие версий. Содержательные вопросы устроены иначе. Достаточно ли тестов для нового режима отказа? Верно ли определён владелец поведения? Сохраняет ли решение архитектурную границу?

Попытка свести такие вопросы к одному score создаёт видимость объективности. Harness должен отмечать точки, где требуется judgment, и передавать их роли с соответствующей authority.

Reviewer при этом не начинает с нуля. Validation готовит контракт, candidate identity, semantic impact, checks, новые и унаследованные ошибки и статус freshness. Человеческое внимание расходуется на смысловые риски, а не на реконструкцию запуска.

Надёжный assurance-слой хранит неизменяемые и воспроизводимые evidence, вычисляет их актуальность относительно точного кандидата и отделяет механическую validation от содержательного judgment.

Как усиливать границы по мере роста harness

Архитектурная граница снижает связанность, но требует инфраструктуры: контрактов, преобразования данных, обработки ошибок, тестов совместимости и правил владения состоянием. В harness к этому добавляется стоимость передачи контекста между ролями и синхронизации рабочих областей.

Поэтому максимальное число границ не свидетельствует о качестве. Изоляция нужна там, где она окупает собственную сложность.

Глава 17 описывает границы как линии между частями системы, которые меняются с разной скоростью и по разным причинам. Их задача — защитить важную policy от преждевременной зависимости. Для harness этот критерий полезнее правила «каждой стадии нужен отдельный агент».

Логическая граница предшествует физической

Роль, процесс, контейнер и сервис относятся к способам исполнения. Они не создают архитектурную независимость автоматически.

Исследователь и исполнитель могут работать в разных процессах, но изменять один общий task record без ограничений. Тогда researcher способен переписать принятый контракт, а implementer — объявить собственный результат проверенным. Физическое разделение существует, границы authority нет.

Одна модель, напротив, может последовательно исполнять две изолированные роли. Research получает read-only доступ и создаёт отчёт. Implementation работает в свежем контексте по принятому контракту и не меняет исходные решения. Логическая граница здесь сильнее физической.

Архитектурную границу определяют разные причины изменения, явный контракт и направленное ограничение полномочий. Изоляция в отдельный процесс или worktree добавляется при требованиях к безопасности, параллельности, отказоустойчивости и независимому исполнению.

Строгость можно наращивать постепенно

Глава 24 вводит partial boundary: архитектор сохраняет направление будущей границы без полной стоимости независимых компонентов.

В harness граница может последовательно принимать разные формы. Сначала появляется документированное соглашение. Facade скрывает внутреннюю структуру механизма. Interface переносит владение контрактом к high-level use case. Schema и validator делают границу данных машинно проверяемой. Отдельная роль добавляет собственные полномочия, а process или worktree изолирует исполнение и побочные эффекты.

Эта последовательность не обязательна для каждой функции. Форматированию диагностического сообщения часто достаточно facade. Review verdict влияет на интеграцию и требует schema, candidate identity, immutable record и отдельной authority.

Допустим, harness пока использует один test runner. Универсальная plugin-платформа создаст больше работы, чем пользы. Можно определить CheckRunner и нормализованный CheckObservation, но оставить реализацию в том же процессе. Второй runner добавится без изменения readiness policy.

Partial boundary нуждается в дешёвой защите. Прямой импорт реализации, общий mutable object или обход validator постепенно превращают её в декорацию. Dependency test, schema validation или ограничение инструментов позволяют удержать направление.

Несколько агентов и сервисов не гарантируют независимость

В главе 27 Мартин показывает, что разные сервисы могут сохранять сильную связь через общие данные и сквозное поведение. С агентами происходит то же самое.

Пять ролей могут обмениваться одним большим JSON-документом. Новое обязательное поле затронет intake, researcher, designer, implementer, reviewer и orchestration. Формально роли разделены, фактически каждая зависит от общей структуры целиком.

Сквозная policy создаёт ещё один вид связи. Если freshness частично реализована в промпте исполнителя, скрипте запуска тестов и инструкции reviewer, изменение правила требует согласованного редактирования трёх механизмов.

Топология исполнения отвечает на вопрос, где работает код. Архитектура показывает, какие изменения распространяются через систему. Граница может проходить внутри одного сервиса, а два сервиса могут принадлежать одному архитектурному компоненту.

Компоненты группируются по совместному изменению

Технические каталоги prompts, schemas, scripts и validators выглядят естественно, но распределяют один use case по всему репозиторию. Изменение review contract требует найти prompt, schema, parser, validator и тесты в разных местах.

Common Closure Principle из главы 13 предлагает группировать вместе то, что меняется по одной причине. Компонент review может содержать контракт роли, schema результата, policy verdict, adapters и относящиеся к ним тесты. Общий механизм выносится после появления нескольких реальных потребителей.

Common Reuse Principle ограничивает обратную крайность. Большой пакет harness-common приносит каждому потребителю типы и зависимости, которыми он не пользуется. Узкие компоненты вроде candidate-identity, evidence-contracts или semantic-query-model оправданы, когда у них появляется самостоятельная причина изменения.

Баланс меняется со временем. В начале близкие функции удобно держать вместе. После появления независимых потребителей часть контрактов становится самостоятельной. Компонентная структура следует за реальными изменениями, а не за заранее выбранной идеальной схемой.

Зависимости должны оставаться ацикличными

Acyclic Dependencies Principle из главы 14 запрещает циклы между компонентами. В цикле несколько модулей фактически становятся одним: их трудно тестировать и изменять отдельно.

Assurance может собирать данные для reviewer, а затем начать импортировать review policy для расчёта собственного статуса. Semantic context может обратиться к reviewer за подтверждением claims, хотя reviewer уже зависит от semantic context. Lifecycle вызывает integration gate, который изменяет lifecycle напрямую.

Такие связи размывают authority и порядок работы. Предпочтительное направление выглядит так:

core contracts
    ↑
lifecycle policy · semantic model · evidence policy
    ↑
use cases
    ↑
adapters · CLI · CI · models · storage
    ↑
composition root

Цикл разрывается через контракт, принадлежащий более высокому уровню, или через новый компонент с общими устойчивыми понятиями. Простое перемещение файлов не меняет зависимость.

Стабильные компоненты с большим числом потребителей должны оставаться расширяемыми. Readiness может зависеть от RequiredCheckPolicy, а конкретные наборы checks определяются конфигурацией домена. Канонический evidence contract сохраняет обязательное ядро и допускает версионированные расширения.

Конкретные модели, runners, хранилища и профили permissions собираются во внешнем composition root. Глава 26 называет его Main component. Остальная система получает готовые зависимости и не читает provider settings или environment самостоятельно. Один core тогда работает в локальном, тестовом, CI и integration-профилях.

Архитектура развивается через локальные миграции

Глава 14 подчёркивает, что структура компонентов не проектируется целиком сверху вниз. Реальные изменения показывают, какие модули связаны, где появляются циклы и что требует защиты.

Архитектурная проблема часто вызывает желание переписать harness целиком. Глава 1 предупреждает, что старт с нуля не устраняет причин прежней сложности. Новый код способен повторить те же решения, если команда не поняла ось изменения.

Безопасная миграция начинается с наблюдаемого затруднения. Допустим, use cases напрямую читают provider-specific ответ модели, поэтому смена SDK затрагивает validation и review. Сначала текущее ожидаемое поведение фиксируется contract tests. Затем появляется канонический результат роли и adapter действующего провайдера. На новый контракт переводится один потребитель, после проверки — остальные. Прямой доступ к старому формату удаляется в конце.

Для рискованных изменений подходит shadow mode: старый путь продолжает принимать решения, новый вычисляет результат параллельно, а расхождения собираются как данные. Authority передаётся после достижения понятного соответствия.

Долгоживущим task contracts, semantic claims, evidence и verdicts нужна явная версия. Новая реализация должна прочитать старый формат, мигрировать его или признать артефакт устаревшим. Молчаливое толкование старого поля по новым правилам опаснее явной ошибки.

Момент усиления границы определяется трением: повторными обходами interfaces, конфликтами authority, ростом области изменения и высокой ценой отказа. Глава 25 предлагает сравнивать стоимость реализации границы со стоимостью её отсутствия и пересматривать решение по мере развития системы.

Строгость границы должна соответствовать различию полномочий, независимости изменений и последствиям ошибки. Архитектура harness развивается через локальные шаги, которые защищают устойчивую policy и оставляют способ исполнения заменяемым.

Единица работы и проверяемый lifecycle

Архитектура harness проявляется на конкретной задаче. Здесь policy, роли, семантический контекст и evidence должны образовать управляемый процесс.

Слишком крупная задача перегружает его: design содержит несколько независимых решений, diff затрагивает несвязанные области, а reviewer вынужден выбирать отдельные участки для проверки. В слишком мелкой задаче значительная часть стоимости уходит на task intake, передачу контекста и интеграцию; поведение продукта распадается между единицами, которые имеют смысл лишь вместе.

Подходящая task unit достаточно мала для конечной и полной проверки, но сохраняет самостоятельный инженерный смысл. Один reviewer должен иметь возможность сопоставить существенный diff с одним принятым контрактом и конечным набором evidence.

Речь не о лимите строк или файлов. Изменение одного поля протокола способно затронуть много consumers. Локальный рефакторинг может изменить сотни строк без нового поведения. Размер определяется количеством независимых решений, архитектурных границ и проверяемых обязательств.

Декомпозиция следует за поведением

Глава 16 описывает use cases как естественные вертикальные срезы системы. Каждый сценарий проходит через интерфейс, прикладные правила, предметную модель и хранение, но сохраняет собственную причину изменения.

Разбиение одной функции по техническим слоям — «изменить schema», «обновить service», «исправить UI» — создаёт три задачи, каждая из которых зависит от будущих решений остальных. Отдельно их трудно проверить на уровне пользовательского поведения.

Вертикальная единица формулируется иначе: добавить статус операции, провести его через владельца состояния и публичный контракт, показать в существующем маршруте и сохранить восстановление после сбоя. Она затрагивает несколько слоёв, но выражает одно намерение и получает определимые acceptance criteria.

Техническая подготовка иногда заслуживает отдельной задачи: миграция, общий adapter или инфраструктурная возможность могут иметь самостоятельный контракт. Зависимость должна быть явной, а результат — проверяемым без обещания неопределённой будущей пользы.

Качественный task contract фиксирует намерение, владельца поведения, scope и non-goals, совместимость, failure policy, затронутых consumers, semantic obligations и критерии assurance. Он не предписывает каждую функцию и имя файла. В контракт попадают решения, от которых зависит продуктовый результат.

Недостаточно определённый contract переносит проектирование на implementation: исполнитель самостоятельно решает вопросы совместимости, а reviewer не может отделить ошибку от допустимой интерпретации. Избыточно подробный contract связывает реализацию с гипотезой проектировщика. Нужна граница между обязательствами и внутренней свободой.

Зависимые задачи образуют DAG

Крупное изменение после декомпозиции превращается в граф. Общий контракт может предшествовать миграции двух consumers, а удаление compatibility layer — зависеть от обеих ветвей.

contract foundation
    ├── consumer A migration
    └── consumer B migration
             ↓
      compatibility removal
             ↓
         integration

Цикл «A завершается после B, а B требует завершённую A» указывает на неверную границу. Задачи нужно объединить или выделить общий prerequisite. ADP из главы 14 применим к единицам работы так же, как к компонентам.

Каждая зависимость ссылается на стабильный артефакт: принятый contract, конкретный candidate или versioned interface. Ссылка на текущую ветку соседней задачи создаёт плавающий вход и разрушает воспроизводимость.

Стадии снимают разные виды неопределённости

Lifecycle нужен для управления вопросами, а не для заданного количества церемоний.

Discovery устанавливает текущее поведение и фиксирует unresolved questions. Design превращает намерение в принятый contract. Decomposition выделяет независимо проверяемые units. Implementation создаёт candidate с точной identity. Assurance организует попытки опровержения и evidence. Review выносит независимый verdict. Integration проверяет authority и freshness его оснований.

Стадии можно объединять. Небольшое локальное исправление с очевидным механизмом не требует отдельной design-кампании. Изменение публичного контракта требует явного решения о совместимости и отказах. Объём процесса следует за риском.

Gate защищает конкретного потребителя. Design gate не передаёт implementer неопределённый контракт. Candidate gate даёт assurance точный объект проверки. Review gate гарантирует наличие релевантного evidence. Integration gate не позволяет устаревшему решению изменить репозиторий.

Проверка наличия документа без связи с потребителем превращает gate в бюрократию. Пустой design удовлетворяет schema, но не снимает неопределённость. Хороший gate проверяет достаточность входа для следующего use case: механические условия устанавливает validator, содержательные — роль с подходящей authority.

Восстановление входит в штатный сценарий

Долгий agentic workflow прерывается: модель достигает лимита, инструмент возвращает временную ошибку, base revision меняется, reviewer запрашивает исправление. История чата не должна оставаться единственным источником состояния.

Возобновление строится из сохранённых authority, contracts, candidate identity, evidence и незавершённых obligations. После сбоя оркестратор находит последнюю завершённую стадию и проверяет актуальность результата. Валидный артефакт используется повторно, а для устаревшего создаётся конкретное обязательство по обновлению.

Эффективность такого lifecycle видна по совокупности сигналов: времени от принятого intent до readiness, объёму человеческого review, возвратам на предыдущие стадии, дефектам после интеграции, stale evidence и области компонентов, затронутых одним изменением. Отдельный показатель легко создаёт неверный стимул. Ускорение implementation может увеличить rework, а рост числа checks — задержать flow без снижения дефектов.

Улучшение полезно, если надёжное изменение требует меньше общих усилий и не переносит расходы на следующий релиз.

Архитектура поднялась на уровень выше

Coding-агент меняет способ производства кода, но не свойства программных систем. Требования продолжают меняться, компоненты развиваются с разной скоростью, внешние инструменты устаревают, а стоимость сопровождения зависит от связанности.

Высокая скорость генерации усиливает влияние архитектуры. Неудачное решение быстрее распространяется по репозиторию. Неполный контекст быстрее превращается в правдоподобную реализацию. Слабая проверка пропускает больше кандидатов за то же время.

Поэтому сильная модель сама по себе не образует инженерную систему. Нужна архитектура среды, в которой модель получает ограниченную задачу, исследует продукт, действует в пределах authority и оставляет проверяемый результат.

Clean Architecture применяется здесь на двух уровнях: к продукту и к harness, который этот продукт изменяет. На втором уровне возникают собственные business rules — contracts, permissions, lifecycle, evidence validity и integration gates. Их нужно защищать от моделей, Git, CI и других механизмов так же, как бизнес-правила приложения защищаются от базы данных или веб-фреймворка.

Практическая ценность книги не сводится к диаграмме из кругов. Она предлагает критерии принятия решений:

  • оценивать архитектуру по стоимости будущих изменений;

  • направлять зависимости от волатильных механизмов к устойчивой policy;

  • проводить границы по причинам изменения и полномочиям;

  • строить тестируемые и фальсифицируемые units;

  • усиливать изоляцию в момент, когда цена её отсутствия становится выше.

В собранном виде процесс начинается с человеческого намерения. Contract ограничивает смысл задачи. Semantic projection ограничивает область поиска. Candidate identity фиксирует объект проверки. Evidence сохраняет наблюдения и их происхождение. Независимый review добавляет judgment. Integration gate подтверждает, что основания решения сохранили силу.

Полную схему не требуется внедрять сразу. Начинать полезно с самой дорогой неопределённости. При ошибках scope поможет семантическая карта с anchors. При расхождениях между задачей и кодом нужен принятый contract. При дорогом review наибольшую пользу дадут candidate identity, provenance и отдельная reviewer authority. Следующий механизм появляется после наблюдаемой проблемы.

Человек остаётся владельцем намерения и значимых компромиссов. Совместимость имеет продуктовую цену, допустимый риск зависит от бизнеса, а две технически корректные альтернативы могут по-разному влиять на сроки и эксплуатацию. Harness автоматизирует механические проверки и поднимает такие решения на уровень подходящей authority.

Зрелость harness определяется не количеством агентов, validators или узлов semantic graph. Полезная система удерживает изменение локальным, выдаёт ролям релевантный контекст, сохраняет происхождение утверждений, отзывает устаревшие результаты, восстанавливается с последнего валидного артефакта и переживает замену модели без переписывания policy.

Все эти свойства сходятся в одной цели: снижать совокупную стоимость надёжного изменения.

Агенты берут на себя всё большую часть инженерного цикла. Архитектурная работа остаётся в выборе границ, формулировании policy и устройстве системы, в которой корректное действие требует меньше усилий, чем опасное.

Автор: murmaaan

Источник