Почему это отдельная заметка
Устройство репозитория под агента (Agent First Repository) отвечает на вопрос, как сделать код доступным агенту. Здесь — обратная сторона: что делать с потоком изменений, который такой репозиторий начинает производить. Темы срослись по истории, но упираются в разные ограничения: там в понятность кода для машины, здесь в объём внимания человека, который не растёт ни от какой инженерии.
Размер изменения как гейт, а не как пожелание
Сделать приложение читаемым для агента — половина ответа на переезд узкого места. Вторая половина — ограничить объём, который вообще доходит до человека, и делать это не просьбой, а проверкой, валящей сборку.
Основание известно задолго до агентов: у человека предел внимательного чтения диффа — порядка двух-четырёх сотен строк, дальше качество ревью падает нелинейно. Агентная разработка не меняет этот предел, а только увеличивает поток, который в него упирается. Наблюдаемая форма — жёсткий потолок в пятьсот строк на изменение, без исключений; исключение здесь опаснее отсутствия правила, потому что делает потолок предметом переговоров.
Тот же вывод независимо получен в другой области — в маршрутизации по стоимости, где у режима «использовать только оплаченное» намеренно нет флага выключения. Довод названный там точнее общего: выключенный режим продолжил бы обслуживать полный набор кандидатов, платные модели включительно, под именем, которое обещает обратное. Обобщённая форма правила такая: выключатель опаснее отсутствия ограничения тогда, когда после выключения имя остаётся прежним, — потому что дальше на это имя опираются, не перепроверяя, что оно ещё значит.
У порядка проверок при этом своя логика: сначала изменение читает агент-ревьюер, вооружённый умениями проекта, и только после его одобрения подключается человек. Смысл не в том, чтобы заменить человека, а в том, чтобы его время тратилось порциями и не уходило на объяснение внешнему участнику того, что записано в правилах проекта. Заодно снимается вторая половина той же проблемы: качество машинного ревью падает с ростом диффа так же, как человеческого, — просто по другой причине.
У этого ограничения есть парное, и без него оно откладывает затор, а не снимает его. Потолок делает единичное изменение пригодным к внимательному чтению, но объём внимания не увеличивает. Когда изменения производит не человек, а плановый цикл, второе ограничение ставится на число одновременно открытых изменений — обычно одно на цикл (Agentic Control Loop). Оба выведены из одной и той же ёмкости приёмки: первое отвечает за размер очереди по одному элементу, второе — за её длину.
Побочный эффект оказался сильнее основного. Ограничение размера само отсекает сгенерированный мусор, и вот почему: агент, работающий без вмешательства, не перерабатывает существующий интерфейс под новую возможность, а надстраивает её сверху. Такие изменения выходят объёмными по построению — и не проходят потолок, не доходя ни до машинного ревью, ни до человеческого. Правило, введённое ради внимания читателя, оказалось фильтром по способу работы.
Формально это противоречит принципу «минимум блокирующих гейтов» из раздела «Пропускная способность меняет процесс» ниже, и противоречие мнимое: там речь о гейтах на сигналах качества — не блокировать слияние из-за нестабильного теста, — а здесь гейт на размере входа. Первый вид гейтов тормозит поток при высокой пропускной способности, второй его как раз и делает возможным.
Альтернативный взгляд: приёмка работающего инкремента вместо ограниченного диффа
Потолок размера лечит нехватку человеческого внимания сужением входа: дифф режется до объёма, который человек ещё читает внимательно. Есть противоположное лекарство от той же нехватки — сменить предмет приёмки, а не его размер.
В этой версии человек перестаёт отвечать за качество кода: его читают и правят агенты — реализующий, тестирующий, проверяющий. Человек принимает работающий инкремент: пользуется возможностью, проходит рабочий сценарий целиком, проверяет важные случаи применения и отвечает на один вопрос — решает ли это заявленную проблему. Запрос на слияние соответственно перестаёт быть диффом и становится предъявлением: что построено, чем это проверено и где это можно потрогать.
Развилка настоящая, потому что ветки ломаются по-разному:
| Потолок размера | Приёмка инкремента | |
|---|---|---|
| что ограничивают | объём входа | предмет проверки |
| где человек | внутри кода, порциями | снаружи кода, на поведении |
| чем ловится дефект | внимательным чтением изменения | прохождением сценария |
| как ломается | поток упирается в потолок, и потолок становится предметом переговоров | проверены только случаи, которые человек догадался пройти |
| что при этом теряется | скорость на широких, но однородных изменениях | связь между наблюдаемым поведением и местом в коде, где его чинить |
Условие применимости различает их лучше, чем спор о принципе. Смена предмета приёмки предполагает, что нижний контур закрыт машиной: тесты, которые агент не имеет права ослабить, чтобы пройти (Generator Evaluator), проверяемые критерии приёмки в спецификации (Verifiable Eval) и работающая обратная связь из эксплуатации. Там, где этого нет, отказ от чтения диффа не переносит проверку на уровень выше, а убирает её: функциональный проход покрывает те случаи, которые пришли в голову проверяющему, и ровно против этого существуют юнит-тесты.
Обратное тоже верно и стоит сказать прямо: потолок размера не масштабируется — он делает человеческое внимание пригодным к употреблению, но не увеличивает его. При росте числа агентных линий обе ветки упираются в один и тот же предел, и вопрос из «как читать дифф» становится вопросом «чем доказывается результат без человека в каждом цикле».
Третья ветка: смотреть выше по течению, потому что там рычаг больше
Обе ветки выше спорят о том, что показывать человеку на выходе. Третья позиция переносит внимание на вход и обосновывает это множителем ошибки:
плохая строка кода — это плохая строка кода; плохая строка плана оборачивается сотнями плохих строк кода; плохая строка исследования — непонимание того, как устроен код и где что лежит, — тысячами.
Отсюда правило распределения внимания: тратить его там, где множитель больше, то есть на исследование и план, а не на дифф. Практическая форма довода честнее любой теории: две тысячи строк на языке, который читаешь ежедневно, прочитать нельзя, а двести строк хорошо написанного плана — можно. Бюджет внимания тот же, отдача разная.
Различие с двумя предыдущими ветками принципиальное и стоит держать его явно:
| Что проверяет человек | Когда | |
|---|---|---|
| потолок размера | изменение кода, порциями | после реализации |
| приёмка инкремента | поведение продукта | после реализации |
| проверка выше по течению | исследование и план | до реализации |
Третья ветка дешевле обеих — правка строки плана стоит минуты, — но требует, чтобы исследование и план существовали как отдельные версионируемые артефакты (AI Native SDLC). Там, где их нет, ветка недоступна: проверять нечего.
Чего она не даёт: гарантии, что реализация соответствует утверждённому плану. Проверка вверху не отменяет нижнюю, она меняет её характер — внизу остаётся сверка «сделано ли то, что написано», и её как раз можно отдать машине.
Ревью нужно не для корректности, а для того, чтобы команда не потеряла продукт
Довод, который переворачивает постановку и в базе не записан нигде. При высокой пропускной способности агентов главным источником боли становятся не дефекты, а утрата понимания собственной системы: наблюдение автора сформулировано прямо — «я начал терять связь с тем, что представляет собой наш продукт и как он работает».
Механика простая и неизбежная: чем больше кода выпускается, тем большая его доля в любой момент незнакома любому инженеру. Это не дефект процесса, а его следствие, и корректность здесь ни при чём — код может быть безупречным и всё равно чужим.
У этого разрыва полезно различать две ступени. Comprehension debt — накопленная разница между работающей системой и ментальной моделью команды; её ещё можно погасить картой системы, спецификациями, демо и выборочным чтением. Cognitive surrender — момент, когда человек перестаёт независимо проверять замысел и принимает вывод агента как замену собственному суждению. Автоматизация способна снизить число дефектов, но не отменяет владение системой; процесс приёмки обязан сохранять evidence и точки, где человек может восстановить причинную цепочку.
Отсюда требование к процессу, независимое от того, какую из трёх веток выбрали: он обязан держать команду на одной странице и давать быстро узнать незнакомую часть кода. Для обычной команды эту роль играют пул-реквесты и внутренние документы; в разобранном случае — исследования, планы и спецификации, потому что их читают, а диффы уже нет.
Практическое следствие для выбора ветки: если предмет приёмки не отвечает ни на один из этих двух вопросов, процесс закрывает корректность и оставляет открытым то, что на длинной дистанции дороже.
Пропускная способность меняет процесс
При высокой пропускной способности привычные инженерные нормы становятся контрпродуктивными: репозиторий работает с минимумом блокирующих гейтов, запросы на слияние короткоживущие, а нестабильные тесты чинят повторным прогоном, а не блокировкой.
Довод сформулирован честно и с границей применимости: когда пропускная способность агентов сильно превышает человеческое внимание, исправления дёшевы, а ожидание дорого. Авторы сами добавляют, что в среде с низкой пропускной способностью это было бы безответственно.
Это прямая развилка для проектирования релизного процесса (ADLC): жёсткость гейтов надо выбирать не по общей норме, а по соотношению цены исправления и цены ожидания в своём контуре.
Устройство ревьюера: передача между этапами, а не один промпт
Предыдущие разделы — про то, что и в каком порядке смотреть. Отдельный предмет — как собран сам агент-ревьюер, и здесь есть свидетельство с необычной для отрасли ценностью: команда прошла пять поколений собственного ревью-агента (одиночный вызов → ReAct → вызовы инструментов → планирование → выделенный ведущий ревьюер) и закончила выводом не писать свой агентный цикл. Цикл заменили готовой обвязкой, поднятой отдельным процессом, а над ней — линейным конвейером на обычном коде; из более чем ста двадцати методов обвязки используется три-пять.
Вывод стоит прочитать точно: отказались не от управления процессом, а от владения циклом. Управление осталось и стало явным — в виде линейного кода, который видно и можно отладить, вместо промпта, который просят вести себя как конечный автомат (Agent Instruction Surfaces).
Три формы оттуда же, переносимые независимо от обвязки.
Типизированная передача между этапами. Результат этапа уходит дальше не свободным текстом, а вызовом специально заведённого инструмента со схемой (submit_review, submit_final_review). Это даёт сразу три вещи: проверку структуры на границе, машиночитаемость без разбора прозы и явный сигнал завершения — «этап закончился» перестаёт быть догадкой по тексту и становится фактом вызова (Structured Output, Unknown Not A Value).
Пара «адвокат и скептик» на каждую неуверенную находку. Спорная находка не отбрасывается и не принимается ведущим в одиночку: её разбирает пара субагентов с противоположными задачами — обосновать и опровергнуть. Существенна деталь реализации: право вынести вердикт отнято у них на уровне конфигурации, а не запрещено в промпте. Это тот же принцип, что и у детерминированного запрета: сторожить надо проводку, а не решение (Guardrails).
Находка, которую некуда поставить, понижается, а не теряется. Привязка к файл:строка нормализуется с допуском в строку, и если якорь не сошёлся, находка уходит в общий комментарий вместо того, чтобы исчезнуть. Правило общее для любого разбора с привязкой к позиции: потеря якоря — это понижение, а не отмена (Unknown Not A Value).
OpenCodeReview усиливает этот приём: модель возвращает не доверенный номер строки, а фрагмент existing_code. Рантайм сначала ищет точное совпадение в изменённых блоках, затем в полном файле и допускает перенос в другой файл только при единственном совпадении. Неоднозначный якорь не превращается в уверенную координату; LLM-релокация остаётся поздним фолбеком. Здесь модель отвечает за смысл замечания, а детерминированный код — за существование и однозначность адреса.
Детерминированный каркас вокруг вероятностного ревью
Полезная граница проходит не между «ручным» и «LLM-ревью», а между решениями, которые можно зафиксировать кодом, и решениями, где нужен семантический анализ. В OpenCodeReview область проверки, фильтрация файлов, приоритет правил, бюджет группы, привязка комментария и учёт исходов выполняются детерминированно; модель ищет дефекты внутри уже ограниченной области.
Selection должна быть одной чистой функцией для preview и запуска. Если предварительный просмотр и фактическое исполнение собирают список файлов разным кодом, оператор утверждает один объём, а агент получает другой. Список кандидатов строится один раз с явным порядком исключений: бинарные и секретные пути → пользовательские include/exclude → типы файлов → generated/default paths → лимит diff. Исключение секретного пути имеет приоритет над пользовательским include.
Группировка включается после порога сложности. Малое изменение объединяется без LLM. Большой набор файлов можно разделить семантически по одним метаданным путей, ограничить число файлов и токены в группе, а при любой ошибке вернуться к «один файл — одна группа». Вероятностная маршрутизация оправдана только там, где улучшает доступный контекст; её отказ не должен лишать ревью покрытия.
Инструменты ревьюера должны быть узкими. Чтение файла, поиск, чтение diff, создание комментария и явное завершение дают агенту достаточно свободы для исследования, не открывая произвольный shell. На каждую операцию ставятся лимиты строк, результатов, времени и итераций (Bounded Tool Output).
Sealed coverage manifest
До диспетчеризации регистрируется и закрывается denominator — полный список выбранных элементов. После старта его нельзя незаметно расширить или сузить, а каждый элемент обязан попасть ровно в один терминальный исход:
selected = completed ∪ reused ∪ failed ∪ waived
complete выводится из полного покрытия denominator, а не из отсутствия ошибок в верхнеуровневом процессе и не из числа комментариев. Для каждого элемента хранятся стабильный ID, fingerprint содержимого и класс отказа; для запуска — разрешённые commit SHA вместо подвижных refs, хеш входного артефакта, правил и runtime-конфигурации, provider/model и concurrency. Возобновление может переиспользовать только исходы, подтверждённые финальным manifest родительского запуска; failed пересматриваются. Это частный случай Batch Close Protocol и Evidence Spine: завершение означает закрытый набор исходов, а не сообщение «все агенты закончили».
Что делать с 52 встроенными профилями правил
В репозитории не 52 универсальных правила, а 52 профиля по языкам и типам файлов — около 2 400 строк инструкций. Их качество неоднородно, поэтому копировать пакет как стандарт нельзя.
- Сильные кандидаты как справочный материал: Go, PHP, Swift, Astro, Prisma, Rego, GraphQL; схемы совместимости Protobuf/Thrift/Cap'n Proto; HDL и smart-contract профили. В них явно названы границы наблюдаемости, версии языка, случаи «не сообщать» и необходимость подтвердить non-local claim через call sites или конфигурацию.
- Только как project policy: naming, обязательные комментарии, конкретные стилистические запреты, требования к pagination, caching, localization и структуре API. Они становятся находкой лишь после подтверждения локальной нормой и не должны изображаться дефектом языка.
- Не переносить: однофразовые проверки орфографии ключей JSON/YAML, безусловный запрет snapshot-версий, универсальные требования
try/catchдля каждой async-функции, советы C «всегдаstrncpyи занулять pointer», запретыany,var, nested ternary и другие правила, которые дублируют линтер либо выдают предпочтение за корректность.
Пакет полезен не содержимым целиком, а форматом: у профиля есть precision posture, граница доступного evidence, версия языка, blocking/non-blocking severity и перечень исключений. Новое правило принимается в проект только после трёх проверок: существует локальный инвариант; находку можно подтвердить из доступного контекста; детерминированный анализатор не делает это надёжнее и дешевле. Иначе правило остаётся справкой для человека, а не обязательной инструкцией агенту.
Разбор, который не сходится: полнота доклада и память между проходами
Закрытый манифест выше делает «завершено» свойством покрытия выбранного объёма в одном запуске. У разбора есть второе измерение, которого манифест не касается: полнота доклада и память между запусками. Проход может честно покрыть каждый файл и сообщить две находки из пяти, которые увидел.
Замеренный случай из трекера самих авторов: на одном запросе на слияние — двенадцать проходов и тридцать семь находок, по две–пять за проход (2, 5, 3, 4, 3, 3, 2, 2, 2, 4, 3, 4). Дефект, видимый в диффе первого круга, назван на шестом. Каждый пуш запускает новый проход, поэтому изменение с большим числом скрытых находок требует по пушу на горсть — и не сходится никогда.
Причины названы в обвязке, а не в модели, и их две.
Нет правила полноты. Промпт не требовал сообщать всё найденное. Формулировка починки стоит того, чтобы её перенять: «не ограничивай, сколько сообщаешь: находка из этого диффа, оставленная на следующий проход, стоит автору ещё одного круга; ранжирует метка серьёзности, список ранжировать не нужно». Последняя часть существенна — ранжирование уходит в метку, а не в обрезку списка.
Нет памяти о прошлых проходах — и её нельзя было попросить. Здесь главная деталь случая. Разбор шёл только на чтение и без токена доступа к хостингу, поэтому прочитать комментарии прошлых проходов он не мог; авторы прямо пишут, что правило в файле инструкций «учитывай прошлые проходы» ничего бы не дало. Прошлые находки подаёт в промпт сам конвейер, с правилом «уже починенное назови снятым и не поднимай снова». Это случай «не может», а не «не велели», и чинится он возможностью, а не указанием (Harness Optimization). Две починки независимы, и ни одна не делает другую лишней. Правило полноты действует уже на первом круге, где прошлых находок нет вовсе, и срезает капание по горсти на каждом круге. Доставка прошлых находок нужна со второго круга и лечит другое — повторное поднятие уже починенного и невозможность назвать находку снятой. Разбор с правилом, но без доставки, всё равно выигрывает на первом круге; разбор с доставкой, но без правила, помнит прошлое и продолжает выдавать по горсти.
Третья причина того же разбора — устаревший вход. Тело запроса на слияние бралось снимком события, то есть в момент пуша; правка описания после пуша этому проходу невидима. В одном проходе это дало ложную блокирующую находку, в другом — две уже починенные. Починка: перечитывать вход непосредственно перед запуском модели. Это по-прежнему снимок, но снятый после обычной правки автора. Та же логика, что у проверки устаревшей записи, только на стороне чтения (Stale Write Guard).
Симптом не единичный: второй, независимый конвейер разбора замерил у себя то же самое — 135 кругов на 15 изменений, в среднем девять, у одного двадцать шесть, — и нашёл в своей сборке промпта ту же недостающую доставку прошлых находок.
Практический вывод — дешёвая диагностика, доступная до всякой починки: если находки приходят по нескольку за круг, а поздние круги называют дефекты, видимые в первом диффе, дело в обвязке, а не в модели. Модель в таком разборе видит достаточно; ей не велят говорить всё и не показывают, что уже сказано.
Порядок чтения: сначала дифф, потом внешний контекст
Отдельное наблюдение той же команды: агент, подводящий итог разбора, привязывается к тому, что прочитал первым. Если сначала подать описание задачи, тикет и переписку, дальнейшее чтение диффа превращается в поиск подтверждений уже сложившейся картины.
Отсюда норма порядка: дифф читается до внешнего контекста, а контекст подтягивается после — для проверки гипотез, а не для их порождения. Приём дешёвый, потому что меняет только порядок шагов, и родственен требованию собирать подтверждения из независимых источников, а не из копий одного (Source Independence).
Метрика доверия — это не метрика качества
Самый поучительный кусок того же опыта — отрицательный, и он нужен как граница.
Та же команда отменила обязательное человеческое ревью: по всем платформам порядка двадцати процентов изменений вливаются вообще без человека, на одной из платформ сорок процентов — без второго ревьюера. При этом метрики качества самого ревью нет никакой: ни доли ложных срабатываний, ни точности, ни независимого оракула; агенту к тому же запрещено исполнение команд, поэтому находка не подтверждается запуском. Открытым вопросом это называют они сами.
Доказательства пользы, которые приводятся, — скорость прохождения изменения и доля вливаний без человека. Вторая величина выглядит как метрика зрелости, а является метрикой доверия, и различие тут не терминологическое: доля вливаний без человека растёт и когда ревью стало не нужно, и когда на него перестали смотреть, — эти два состояния она не различает по построению (Quality Metric Design).
Контрдовод приходит из той же отрасли и того же года: у другой крупной команды объём ревью вырос, а время, потраченное на ревью, — нет. Прочитывается это однозначно: люди стали смотреть меньше, а проблемой это быть не перестало. То есть величина «сколько прошло без человека» может расти просто потому, что внимание кончилось раньше, чем очередь.
Отсюда требование к критерию выхода из обязательного человеческого ревью: он должен быть свойством, а не долей. «Изменения такого класса проходят с механическим доказательством сделанности» проверяемо; «восемьдесят процентов уже проходят без человека» — описание сложившейся практики, выданное за её обоснование.
Контрастный случай из того же поля показывает, как выглядит противоположный выбор. Другая команда человеческую приёмку сохранила и обвесила её измерением деградации — долей критичных дефектов, найденных на приёмке и в проде, до и после внедрения агентов, — плюс явной картой того, что остаётся человеку: замоканное железо, вёрстка, безопасность, исследовательское тестирование. Разница с предыдущим случаем не в степени смелости, а в направлении измерения: там мерили, сколько прошло без человека, здесь — что изменилось в том, что доходит до пользователя. Вторая величина умеет упасть и тем самым отменить решение; первая умеет только расти.
Связано с
- Agent First Repository — устройство репозитория, порождающего этот поток изменений
- AI Native SDLC — цепочка артефактов, к верхним звеньям которой уходит третья ветка приёмки
- Agentic Control Loop — ограничение числа одновременно открытых изменений: та же ёмкость приёмки с другой стороны
- ADLC — релизный процесс, для которого раздел о пропускной способности задаёт развилку
- Parallel Agent Dispatch — ревью как рычаг при нескольких параллельных агентах
- Generator Evaluator — машинный нижний контур, без которого смена предмета приёмки убирает проверку, а не переносит её
- Verifiable Eval — проверяемые критерии приёмки как условие той же смены
- Instruction Compliance Measurement — как убедиться, что принятые правила ревью действительно исполняются
- Quality Metric Design — почему доля вливаний без человека не является метрикой качества ревью
- Instruction Hierarchy — файлы инструкций проверяемого дерева, которые прочтёт судящий агент
- Evidence Spine — manifest запуска как доказательство полного покрытия выбранного объёма
- Stale Write Guard — устаревание на стороне записи; разбор, читающий снимок события, — тот же класс на стороне чтения
- Batch Close Protocol — алгебра терминальных исходов для параллельного ревью
- Bounded Tool Output — ограничения чтения, поиска и числа итераций ревьюера