Files
BlackboxBook/book/16_code_architecture.md
busya 8c176fb89d review: style fixes, empty section removal, numbering fixes, H3 consistency, typo fix
- Удалена пустая секция 14.4.2 (Circular validation)
- Исправлена нумерация: 23.11 → 23.10
- Убрана проза после «Источников» в главе 14
- Ненумерованные H3 в главах 13, 14, 19 — убрана числовая нумерация
- Глава 10: Termination Conditions повышен до ## (был ошибочно вложен в ## 10.5)
- Глава 24: опечатка «простой» → «прост», строчная «глава» → «Глава»
2026-08-12 12:25:52 +03:00

76 KiB
Raw Permalink Blame History

ГЛАВА 16. АРХИТЕКТУРА КОДА, ДРУЖЕСТВЕННАЯ ИИ

В 2026 году ваш код читают не только коллеги — его читают AI-агенты. Claude Code, Cursor Agent, Windsurf, Devin — это не «помощники», это полноценные потребители вашей кодовой базы. Они индексируют файлы, парсят функции, строят граф зависимостей. И качество их работы напрямую зависит от того, как ваш код организован.

Примечание: Эта глава — об архитектуре кода, и примеры «до/после» — её основной обучающий инструмент. Фрагменты ниже — иллюстративный псевдокод, показывающий паттерны и анти-паттерны. Для генерации production-кода используйте AI-промпты, приведённые в каждой секции.

Прежде чем разбирать принципы — посмотрите на реальную ситуацию.

Код, который сломал AI-агента

Команда попросила Cursor Agent добавить скидку для оптовых заказов. Вот что агент увидел:

# app.py — 1200 строк, фрагмент
class App:
    def handle(self, req):
        d = self.db.get(req.args["id"])
        if d and d[7] > 0:  # d[7]? Что это??
            p = d[3] * d[5]  # d[3]? d[5]??
            if self._check(d):  # Что проверяет?
                p = p * 0.9     # Магическое число
            self._do(d, p)      # Что делает?
        return {"ok": True}

Агент не понял, где цена, где количество, что за d[7], и сгенерировал код со скидкой, применённой не к тому полю. Баг ушёл в прод.

Та же логика, переписанная в стиле, дружественном для ИИ, — файл order/pricing.py на 45 строк: типизированная функция calculate_order_price(items: list[OrderItem], discount_percent: float) -> OrderTotal с docstring, описывающим аргументы, возврат и семантику. Cursor Agent получил задачу «добавить оптовую скидку 15% при заказе от 100 единиц». Он прочитал контракт, увидел discount_percent, добавил одно условие — и всё заработало с первого раза.

Промпт для генерации кода: «Напиши Python-модуль order/pricing.py (< 50 строк). Функция calculate_order_price(items: list[OrderItem], discount_percent: float = 0.0) -> OrderTotal. Docstring в Google style с Args, Returns. Используй Decimal для денежных расчётов. Dataclasses для OrderItem (quantity, unit_price) и OrderTotal (subtotal, discount_amount, final_total).»

Вывод: архитектура кода — это уже не только про людей. Это протокол общения с AI-инструментами, которые пишут, рефакторят и ревьюят ваш код каждый день.


16.1. Маленькие модули лучше монолита

Почему модель ошибается в монолитном коде

Представьте кубики LEGO. Каждый кубик — простой: 2×4, красный, с пупырышками. Но из сотни таких кубиков можно собрать что угодно — от домика до космического корабля. А теперь представьте, что вместо кубиков вам дали гипсовый монолит в форме замка. Хотите добавить башню? Нужно ломать стену, надеяться, что крыша не обвалится, и подпирать конструкцию изолентой.

Так же AI-агенты работают с вашим кодом. Маленькие модули — это LEGO-кубики: каждый делает что-то одно, его легко понять, заменить или скомбинировать. Монолит — это гипсовый замок: тронешь одно — сломается другое.

LLM обрабатывает код как последовательность токенов с ограниченным окном контекста. В 2026 году это особенно важно: Copilot, Cursor и Windsurf автоматически индексируют вашу кодовую базу, и маленькие файлы помещаются в их контекстное окно целиком. Монолитный файл в 2000 строк создаёт несколько проблем:

1. Размывание внимания: в файле на 2000 строк (~600010000 токенов) внимание распределяется на множество функций, классов и import'ов. Когда модель модифицирует функцию на строке 1500, она «видит» функцию на строке 50, но уделяет ей минимум внимания (Lost in the Middle).

2. Неявные зависимости: в монолите зависимости скрыты. Функция process_order() на строке 800 может зависеть от глобальной переменной на строке 12, вспомогательной функции на строке 300 и класса на строке 600. Модель должна отследить все эти связи — Transformer умеет это делать, но каждая дополнительная связь увеличивает вероятность ошибки.

3. Переполнение контекста: если файл не помещается в окно контекста — модель работает с фрагментом. Изменение одного фрагмента без видимости другого -> несогласованности.

Оптимальный размер модуля

Размер файла Токены (Python) Качество генерации Рекомендация
<100 строк ~300500 Отлично Идеал
100300 строк 5001500 Хорошо Приемлемо
300500 строк 15002500 Средне Рефакторить
500+ строк 2500+ Ненадёжно Разбить обязательно

Правило: один модуль ≤ 100 строк, одна функция ≤ 30 строк, одна ответственность.

Как это выглядит на практике

До (монолит): order_service.py — 800 строк. Класс OrderService с семью методами: create_order (100 строк), validate_order (60), calculate_price (80), apply_discount (40), process_payment (120), send_notification (50), update_inventory (70) + helpers, constants, error handlers.

После (модули):

order/
├── __init__.py
├── models.py          # 40 строк: Order, OrderItem, OrderStatus
├── validation.py      # 60 строк: validate_order()
├── pricing.py         # 80 строк: calculate_price(), apply_discount()
├── payment.py         # 70 строк: process_payment()
├── notifications.py   # 50 строк: send_notification()
├── inventory.py       # 50 строк: update_inventory()
└── service.py         # 60 строк: create_order() — оркестрация

Каждый файл — это отдельный LEGO-кубик. Он помещается в один промпт с запасом. AI-агент (будь то Claude Code, Cursor или Devin) может модифицировать pricing.py, не загружая весь сервис. А при ревью кода автоматические инструменты парсят каждую функцию отдельно — чем чище контракт, тем точнее ревью.


16.2. Контракт функции как фиксатор смысла

Зачем нужен контракт

Контракт функции — это этикетка на продукте. Когда вы берёте с полки йогурт, вам не нужно его открывать, чтобы понять: состав, калорийность, срок годности — всё на этикетке. Точно так же работает контракт функции: типы аргументов (состав), docstring (описание), тип возврата (результат) — всё видно без чтения тела функции.

Это семантический якорь для модели (Глава 1). Типы, докстроки, pre/post-conditions — всё это фиксирует, что функция делает, не заставляя модель угадывать. В 2026-м это особенно критично: AI-инструменты ревью кода (встроенные в GitHub, GitLab, Cursor) парсят каждую функцию отдельно — чистый контракт = точное автоматическое ревью.

Минимальный контракт

Минимальный контракт включает: имя функции (семантика), типы аргументов и возврата (формат данных), docstring (спецификация поведения), раздел Raises (граничные условия), пример использования (конкретный I/O для калибровки). Без контракта модель вынуждена угадывать формат, поведение и границы.

Промпт для генерации кода: «Напиши Python-функцию calculate_order_total(items: list[OrderItem], discount_percent: float, tax_rate: float) -> OrderTotal. Контракт: items — непустой список, discount_percent и tax_rate — дроби [0.0, 1.0]. Скидка применяется до налога. Добавь Google-style docstring с Args, Returns, Raises (ValueError на невалидные аргументы) и Example с конкретным расчётом. Используй Decimal для точных денежных расчётов.»

Что даёт контракт модели

Элемент Что фиксирует для модели Без контракта
Имя функции Семантика (calculate = вычислить) Угадывает из контекста
Типы аргументов Формат входных данных Может принять str вместо float
Типы возврата Формат выходных данных Может вернуть dict вместо dataclass
Docstring Полная спецификация поведения Угадывает по имени
Raises Граничные условия Может проигнорировать ошибки
Example Конкретный I/O для калибровки Нет якоря для формата

Комментарии: полезен intent, а не пересказ кода

Есть соблазн думать, что для AI чем больше комментариев, тем лучше. Это не совсем так. Современные исследования по code translation показывают, что особенно полезны комментарии о намерении: зачем нужен модуль, какова общая цель функции, какой контракт или инвариант должен сохраняться. А вот комментарии уровня «увеличиваем i на 1» нередко добавляют шум и даже ухудшают трансформации кода.

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

GRACE: semantic header как карта файла

Для AI-агента лучший файл — это файл, у которого смысл виден сверху вниз. Перед телом модуля полезно поставить короткий машиночитаемый заголовок: что делает модуль, с чем связан, какой инвариант защищает и какие опасные пути уже отвергнуты.

# [DEF:OrderPricing:Module]
# @PURPOSE: Рассчитать итоговую цену заказа.
# @LAYER: Domain
# @RELATION: DEPENDS_ON -> [DiscountPolicy:Module]
# @INVARIANT: Скидка применяется до налога.
# @RATIONALE: Денежная логика централизована в одном модуле.
# @REJECTED: Не вычислять цену повторно в API-слое.
# [/DEF:OrderPricing:Module]

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

Почему это имеет смысл. Работы по code generation показывают, что полезен не любой комментарий, а именно слой требований и намерений. В TOSEM-статье ShortenDoc DocString рассматривается как носитель пользовательских требований; авторы показывают, что обычные методы prompt compression для code generation начинают заметно деградировать уже около 10% сокращения, тогда как специализированный docstring-подход даёт 2540% compression без потери качества в условиях их эксперимента. Это признак того, что короткая intent-спецификация содержит концентрированную полезную информацию. При этом MSR-исследование про contextual data в code completion показывает более нюансированную картину: помогают прежде всего осмысленные multi-line comments, а не любое дополнительное текстовое украшение.

Отсюда практическое правило: header должен кодировать purpose / invariants / relations / rejected paths, а не пересказывать построчно реализацию. Сложностные уровни, лимит 300 строк и прочие governance-правила можно смело использовать как дисциплину команды — но честно: это уже не «физика трансформера», а ваша рабочая политика.

Semantic markup без валидатора быстро деградирует

Разметка становится инженерной системой только тогда, когда у неё есть автоматическая проверка. Если semantic header существует лишь как красивый комментарий, через несколько спринтов он начинает врать: закрывающие теги расходятся, @RELATION указывают на удалённые узлы, а старые @REJECTED молча исчезают.

Практический минимум — дешёвый deterministic checker, который проверяет:

  • у каждого [DEF] есть парный [/DEF];
  • обязательные поля header'а не потерялись;
  • @RELATION указывают на существующие public/shared узлы;
  • file-local contracts не утекли в shared graph случайно;
  • нарушение правил даёт non-zero exit code в CI.

Для таких semantic envelopes полный AST не всегда лучший первый инструмент. AST отлично понимает структуру кода, но плохо подходит для comment-level contracts и machine-readable headers. Поэтому на практике хорошо работает гибрид: регулярные выражения и построчный валидатор для semantic boundaries плюс AST только там, где действительно важно проверить imports, callable names или topology.

$ python tools/check_semantics.py
ERROR app/services/pricing.py: missing closing [/DEF:OrderPricing:Module]
ERROR appgraph.xml: unknown relation target [DiscountPolicy:Module]
WARN  tests/test_pricing.py: helper block has no anchor

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

Pre/Post-conditions и Design by Contract

Ещё мощнее — контракт с явными pre/post-conditions и инвариантами. Для функции transfer_funds(from_account, to_account, amount) pre-conditions фиксируют: amount > 0, достаточный баланс, разные счета, оба активны. Post-conditions гарантируют: баланс отправителя уменьшился, получателя увеличился, транзакция залогирована. Инвариант: суммарный баланс не изменился. Pre/post-conditions записываются и в docstring, и как executable assertions в теле функции.

Модель видит pre/post-conditions и генерирует код, который по конструкции их соблюдает. Без них — каждое ограничение нужно угадывать.

Промпт для генерации кода: «Напиши Python-функцию transfer_funds(from_account: Account, to_account: Account, amount: Decimal) -> TransferResult с Design by Contract. Добавь в docstring: Pre-conditions (amount > 0, достаточный баланс, разные ID, активные счета), Post-conditions (балансы изменены, транзакция залогирована), Invariant (суммарный баланс неизменен). Реализуй pre- и post-conditions как executable assertions.»


16.3. Zero-Context Survival: код должен быть понятен без промпта

Тест на автономность

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

Код, сгенерированный ИИ, должен быть полностью самодокументированным — работать и быть понятным без оригинального промпта. Это критерий качества:

Вопросы для проверки:

  1. Может ли новый разработчик понять функцию, прочитав только код?
  2. Все ли зависимости явны (imports, типы, конфигурация)?
  3. Понятны ли границы ответственности (что функция делает и чего НЕ делает)?
  4. Есть ли обработка ошибок для реальных сценариев?

Антипаттерн: контекстно-зависимый код

Функция process(data) без типов, с обращением к item[2], неизвестным threshold и загадочной transform — требует промпт для понимания. В противоположность — самодокументированная filter_high_temperature_readings с typed dataclass SensorReading, явным порогом threshold_celsius и однострочной реализацией. Второй вариант не требует контекста: новый разработчик или AI-агент поймёт всё из сигнатуры.

Промпт для генерации кода: «Рефакторинг: есть функция process(data), которая фильтрует элементы по неявному порогу threshold и применяет неявную transform. Перепиши в Zero-Context Survival стиле: создай frozen dataclass SensorReading (sensor_id, timestamp, temperature_celsius), напиши функцию filter_high_temperature_readings(readings: Sequence[SensorReading], threshold_celsius: float = 40.0) -> list[SensorReading]. Все зависимости явные, типы на всех аргументах.»


16.4. "Small Simple Blocks": линейный код лучше переусложнённого DRY

Проблема чрезмерной абстракции

DRY (Don't Repeat Yourself) — полезный принцип, но его чрезмерное применение создаёт проблемы для AI-генерации.

Переабстрагированный код — это иерархия PricingStrategy(ABC)StandardPricingDiscountPricing + DiscountFactoryBulkDiscount / NoDiscount. Шесть классов, три уровня косвенности — чтобы посчитать subtotal × (1 - discount). Модель должна отследить всю цепочку, чтобы понять, что делает одна операция.

Линейный код — одна функция calculate_order_price(items, discount_percent) -> Decimal: посчитать subtotal, применить скидку, вернуть результат. Три строки логики, нулевая косвенность.

Промпт для генерации кода: «Напиши Python-функцию calculate_order_price(items: list[OrderItem], discount_percent: float = 0.0) -> Decimal. Линейный стиль, без Strategy pattern. Посчитай subtotal как сумму quantity × unit_price, примени скидку, верни результат. Документируй в Google-style docstring.»

Почему линейный код лучше для AI

  1. Меньше косвенности: модель не должна отслеживать цепочку Strategy -> Factory -> Discount -> apply().
  2. Все шаги видимы: в линейном коде каждый шаг — одна строка. В абстрактном — каждый шаг спрятан за интерфейсом.
  3. Модификация проще: чтобы изменить расчёт, достаточно изменить одну функцию, а не всю иерархию.
  4. Тестирование проще: один вход → один выход, без моков и dependency injection.

Когда абстракция оправдана

Критерий Линейный код Абстракция
Вариантов < 3 if/elif Strategy pattern
Код используется 12 раза Дублирование Helper function
Логика < 30 строк Inline Отдельный класс
Требования стабильны Прямой код Зависит
Требования часто меняются Зависит Абстракция с контрактом
Вариантов > 5 Спагетти Strategy/Registry

Правило WET (Write Everything Twice): дублируйте код до тех пор, пока не увидите три одинаковых фрагмента. Тогда — и только тогда — абстрагируйте. Преждевременная абстракция опаснее дублирования.


16.5. Как писать код, который AI легко модифицирует

Принципы кода, дружественного ИИ

1. Явные зависимости через аргументы (Dependency Injection простыми словами):

Dependency Injection звучит сложно, но идея простая: вместо того чтобы функция сама доставала себе всё нужное из глобальных переменных, она получает всё через аргументы. Представьте: вместо «я сам пойду в магазин за молоком» — «передайте мне молоко в руки». Для AI-агента это означает: он видит все зависимости прямо в сигнатуре, не рыская по всему проекту. Пример: вместо get_user(), которая обращается к глобальным db и current_user_idget_user(db: Session, user_id: int) -> User | None.

2. Один файл = одна концепция:

# ✗ models.py — 500 строк с User, Order, Product, Payment, Notification

# ✓ 
models/
├── user.py       # User, UserRole
├── order.py      # Order, OrderItem, OrderStatus  
├── product.py    # Product, Category
├── payment.py    # Payment, PaymentMethod
└── notification.py # Notification, NotificationType

3. Конфигурация через переменные, не через код:

Вместо magic numbers (if retry_count > 3 and elapsed > 30) — именованные константы MAX_RETRIES = 3, TIMEOUT_SECONDS = 30 с использованием в условии и информативным сообщением об ошибке. AI-агент сразу понимает семантику и может безопасно изменить значение.

4. Тесты рядом с кодом (почему это критично для AI-агентов):

AI-агенты (Claude Code, Cursor Agent, Devin) работают циклично: написал код → запустил тест → увидел ошибку → исправил. Если тест лежит рядом с кодом, агент находит его мгновенно. Если тесты в отдельной папке tests/ с другой структурой — агент тратит токены на поиск и может обновить не тот файл. Кроме того, агент использует тесты как спецификацию: тест показывает, что функция должна делать, какие краевые случаи важны.

pricing/
├── __init__.py
├── calculator.py
├── test_calculator.py    # Рядом с кодом, а не в отдельной папке tests/
└── conftest.py

Модель видит тест рядом с реализацией → может обновить оба одновременно.


16.6. Как AI-агенты читают ваш код

Что видит агент, когда открывает проект

В 2026 году AI-агенты — это не просто автокомплит. Claude Code, Cursor Agent, Windsurf, Devin — это полноценные «разработчики», которые навигируют по проекту, читают файлы, запускают тесты и коммитят код. Понимание того, как они это делают, позволяет писать код, который они обрабатывают эффективно.

Шаг 1: Индексация структуры. Агент начинает с дерева файлов. Он видит имена файлов и папок — это его первая карта. order/pricing.py сообщает больше, чем utils/helpers2.py.

Шаг 2: Чтение ключевых файлов. Агент читает конфигурационные файлы (README, pyproject.toml, package.json), затем — файлы, релевантные задаче. У каждого агента ограниченное контекстное окно, поэтому он выбирает, какие файлы загрузить.

Шаг 3: Семантический поиск. Современные IDE (Cursor, Windsurf, Copilot в VS Code) создают эмбеддинги вашего кода. Когда агент ищет «где вычисляется цена заказа», он находит calculate_order_price() по семантическому сходству — но только если имя функции осмысленное.

Шаг 4: Навигация по зависимостям. Агент переходит от функции к её зависимостям через import'ы и type hints. Явные типы = быстрая навигация. Неявные globals = слепое блуждание.

Шаг 5: Цикл редактирования. Агент вносит изменение, запускает тесты, анализирует ошибки. Чем быстрее этот цикл — тем лучше результат.

Что помогает, а что мешает агенту

Помогает Мешает
Осмысленные имена файлов и функций utils.py, helpers.py, misc.py
Type hints на всех публичных функциях def process(data) без типов
README с описанием архитектуры Нет документации проекта
Тесты рядом с кодом Тесты в отдельной иерархии tests/
Маленькие файлы (< 100 строк) Файлы на 1000+ строк
Явные import'ы Магические __getattr__, метапрограммирование
.cursorrules / AGENTS.md с инструкциями Неявные конвенции «у нас так принято»

Overview graph, AST graph и raw code: почему нужен гибрид

Спор «семантический обзор vs AST-граф» неверно ставить как выбор одного победителя. Разные слои решают разные задачи.

AST/dataflow-слой полезен, когда агенту нужно пройти многошаговую цепочку зависимостей: controller -> service -> repository, интерфейс -> реализация, producer -> consumer. Здесь структурный retrieval действительно выигрывает. DraCo строит repo-specific context graph через dataflow analysis и в своей экспериментальной конфигурации улучшает repository-level code completion в среднем на 3.43% exact match и 3.27% identifier F1 (Cheng et al., ACL 2024). Работа Reliable Graph-RAG for Codebases показывает похожий вывод для архитектурных и code-tracing запросов: детерминированный AST-derived graph даёт более надёжное покрытие и multi-hop grounding, чем vector-only baseline и LLM-extracted graph.

Но production-практика важна не меньше. Cursor документирует codebase indexing через embeddings for each file, а Kilo Code — через Tree-sitter semantic blocks + embeddings + Qdrant. То есть реальные агенты часто используют AST и парсинг как основу индексирования и chunking, а не как единственный интерфейс, с которым модель потом «разговаривает».

Intent/overview-слой решает другую задачу: быстро понять, что это за модуль, ради чего он существует и какие ограничения уже известны. Здесь особенно полезны @PURPOSE, @INVARIANT, @RATIONALE, @REJECTED и верхнеуровневые relations. SpecRover показывает, что specification inference внутри LLM-агента повышает качество генерации патчей: в статье сообщается о росте более чем на 50% относительно AutoCodeRover на полном SWE-Bench (Ruan et al., ICSE 2025). А работа Your Coding Intent is Secretly in the Context показывает, что намеренное восстановление авторского замысла перед completion даёт более 20% относительного выигрыша на задачах уровня целого репозитория — в условиях их эксперимента.

Для дружественной ИИ кодовой базы лучше работает многослойный паттерн:

  1. Слой обзора и намерения — что это за модуль и чего нельзя ломать.
  2. Структурный слой — AST, imports, dataflow, call edges.
  3. Слой привязки к коду — чтение реального кода перед финальной правкой.
  4. Слой тестов и проверки — тесты и postconditions после изменения.

Это именно тот класс практик, куда логично помещать GRACE. Он не отменяет AST и не заменяет raw code; он даёт модели короткую карту местности перед тем, как она войдёт в детали.

Public truth vs private truth: двухуровневый интерфейс репозитория

Одна из самых полезных идей, которая хорошо оформлена в grace-marketplace, — жёсткая граница между shared/public truth и file-local/private truth.

Shared/public truth — это артефакты уровня проекта: requirements.xml, development-plan.xml, knowledge-graph.xml, verification-plan.xml. Они отвечают на вопросы:

  • какие модули вообще существуют;
  • каковы их публичные контракты и зависимости;
  • какие verification-entry и critical flows к ним привязаны;
  • в каком порядке их безопасно реализовывать или менять.

File-local/private truth — это уже заголовок и внутренняя разметка конкретного файла: MODULE_CONTRACT, MODULE_MAP, локальные контракты функций, semantic blocks, CHANGE_SUMMARY, а в варианте GRACE-подобной markdown-разметки — [DEF], @PURPOSE, @RATIONALE, @REJECTED и т. п.

Почему такое разделение важно:

  1. Shared-артефакты не распухают. Если knowledge graph начинает перечислять каждый private helper, он превращается из карты страны в снимок всех кухонь сразу.
  2. Снижается drift. Публичная граница меняется реже, чем внутренняя реализация. Значит, общий слой синхронизировать проще.
  3. Агенту легче выбрать глубину чтения. Сначала он читает boundary-level truth, и только потом — implementation detail в целевом файле.

Практическое правило: shared docs должны отвечать на вопрос «что за модуль и как он связан с другими?», а file-local markup — на вопрос «что именно здесь можно безопасно менять и чего делать нельзя?».

Репозиторий как интерфейс запросов для агента

Важный сдвиг в поздних версиях grace-marketplace — появление слоя запросов, понимающего схему. CLI и навыки репозитория разделяют два режима чтения:

  • grace module find/show — доступ к shared/public модульной картине;
  • grace file show --contracts --blocks — доступ к local/private контрактам и semantic blocks конкретного файла.

Это очень сильная идея для агентной разработки. Вместо того чтобы каждый раз гнать модель через голый grep, полезно дать ей два разных API чтения:

  1. найти релевантный модуль и его публичный контекст;
  2. после этого открыть только нужный файл и только его важные секции.

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

Минимальный рабочий паттерн для кодового агента выглядит так:

grace module find auth
→ grace module show M-AUTH --with verification
→ grace file show src/auth/index.ts --contracts --blocks
→ только потом чтение/редактирование сырого кода

Это не отменяет embedding search и AST traversal. Скорее наоборот: semantic search помогает найти кандидатов, structural graph помогает пройти multi-hop зависимости, а слой запросов даёт короткую проверенную выжимку, с которой агент начинает работу.

Практика 2026: патч не в один выстрел, а через короткий цикл поиска и проверки

Метаобзор 2026 года по механике LLM полезен именно тем, что соединяет проектирование запросов, обучение в контексте и масштабирование вычислений на этапе инференса в одну инженерную картину. Для кодовых задач из этого следует очень прикладной вывод: качество патча определяется не красотой одной формулировки, а качеством цикла — как агенту показали формат задачи, сколько вариантов он пробует и чем эти варианты проверяются.

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

2. Порождайте несколько патчей только там, где поиск действительно нужен. Для переименования, мелкого CRUD и однотипных правок хватит одного прохода и тестов. Для миграции схемы, неоднозначного багфикса, сложного SQL, оптимизации алгоритма или многофайлового рефакторинга лучше сразу закладывать 35 кандидатов патча и выбирать лучший по верификатору. Это дешевле, чем десять раз просить одну и ту же модель «подумать ещё» в том же контексте.

3. Пусть побеждает верификатор, а не риторика модели. Для кода внешний верификатор почти всегда сильнее внутреннего самообъяснения. Базовый стек: pytest, типизация (mypy или pyright), линтер (ruff/eslint), проверка схемы, контрольный дифф, интеграционный smoke-тест. Практическое правило простое: выбирайте самый маленький дифф, который проходит проверки и не ломает инварианты.

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

Промпт для генерации кода: «Собери пайплайн generate_patch_candidates(task, repo_context) на Python. Вход: описание задачи, список целевых файлов, инварианты, команды верификации. Шаги: (1) сгенерировать 3 кандидата патча в едином формате, (2) прогнать для каждого тесты, линтер и типизацию, (3) выбрать минимальный дифф, прошедший все проверки, (4) вернуть best_patch, verification_report, rejected_candidates. Используй asyncio для параллельного прогона проверок.»

Калибруйте шаблон на истории реального репозитория

Лучший промпт для кода не угадывают, а подбирают на собственных задачах. Возьмите 2030 реальных тикетов из истории проекта и сравните 23 версии каркаса: например, «короткий план + diff» против «только диффа», или «один кандидат» против «3 кандидата + верификатор». Смотрите не на красоту объяснения, а на инженерные метрики:

  • долю задач, где патч проходит тесты с первой попытки;
  • число ручных правок после ответа агента;
  • точность выбора файлов;
  • среднюю стоимость одного успешно закрытого тикета.

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

Иерархия инструкций защищает агента от заражённого контекста

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

  1. Задача пользователя и критерии приёмки.
  2. Правила репозитория: AGENTS.md, .cursorrules, контракты модулей, тесты.
  3. Структурные факты: типы, AST, imports, dataflow.
  4. Нестабильный контекст: issue-описания, старые комментарии, внешние вставки и примеры.

Если README противоречит тесту, доверяйте тесту. Если комментарий спорит с контрактом функции, доверяйте контракту. Если внешний фрагмент кода предлагает «срезать угол», но нарушает инвариант из @INVARIANT, агент должен отклонить такой путь, а не послушно продолжать. Для production-команды это одна из самых дешёвых и полезных защит: она одновременно улучшает качество патчей и снижает риск того, что агент подхватит вредное указание из неавторитетного контекста.

Пример: как имена файлов влияют на агента

# ✗ Агент не понимает, где искать
src/
├── utils.py          # 400 строк всего подряд
├── helpers.py        # Ещё 300 строк
├── core.py           # «Ядро» из 800 строк
└── main.py

# ✓ Агент находит нужное за секунды
src/
├── auth/
│   ├── login.py
│   ├── tokens.py
│   └── permissions.py
├── orders/
│   ├── pricing.py
│   ├── validation.py
│   └── fulfillment.py
└── notifications/
    ├── email.py
    └── sms.py

16.7. Деградация кода при long-horizon генерации: уроки SlopCodeBench

Проблема: код проходит тесты, но становится немодифицируемым

До 2026 года все основные бенчмарки для coding agents оценивали одно: проходит ли код тесты сейчас. SWE-bench, HumanEval, LiveCodeBench — все они измеряют snapshot correctness. Вы чините баг, код проходит тесты — успех. Что происходит с этим кодом через неделю, месяц, десять итераций — никого не волновало.

SlopCodeBench (Orlanski et al., 2026) показал то, о чём инженеры догадывались: агентный код деградирует. Причём предсказуемо и измеримо.

Эксперимент: 20 задач, каждая — цепочка из 38 чекпоинтов. Агент получает спецификацию, пишет код. Затем — расширенную спецификацию (новые требования) и обязан модифицировать собственный код с предыдущего шага. Никаких reference solutions, никаких подсказок. Только то, что он сам написал раньше.

Результаты по 11 моделям (включая Opus 4.6, GPT-5.4, Sonnet 4.6):

  • Ни одна модель не решила ни одной задачи end-to-end. Лучший strict solve rate: 17.2% (Opus 4.6).
  • Verbosity растёт в 89.8% траекторий. Агенты генерируют дублирующийся код, identity-конструкции, никому не нужные промежуточные переменные.
  • Structural erosion растёт в 80% траекторий. Сложность концентрируется в fewer функциях — там, где вносились правки. Типичная картина: функция main() раздувается с 84 строк до 1099, cyclomatic complexity с 29 до 285.
  • Агентный код в 2.2× более verbose, чем человеческий. Сравнение с 48 поддерживаемыми open-source репозиториями.
  • Качество кода расходится с человеческим всё сильнее от итерации к итерации. У людей erosion и verbosity plateau; у агентов — монотонный рост.

Два измеримых симптома

SlopCodeBench вводит две метрики качества, не зависящие от тестов:

1. Structural Erosion (структурная эрозия). Доля complexity mass, сосредоточенная в функциях с cyclomatic complexity > 10. Формула: mass(f) = sqrt(CC(f) × SLOC(f)). Erosion = Σ mass высоко-CC функций / Σ mass всех функций.

Если коротко: erosion измеряет, не сваливается ли вся логика в одну функцию. В хорошем коде сложность распределена. В сгенерированном агентом — концентрируется в местах, которые он трогал.

2. Verbosity. Доля строк, которые являются (а) дубликатами или (б) подпадают под AST-patterns «пустой» логики. Примеры: identity list comprehension вместо filter, переменные, использованные ровно один раз, избыточные проверки.

Почему так происходит

Корень проблемы — не в «глупости» моделей, а в механике итеративной генерации:

  1. Агент патчит, а не рефакторит. Когда приходит новое требование, агент добавляет elif в гигантский if/elif вместо выделения стратегии. Это рационально: патч дешевле рефакторинга в моменте. Но после 5 итераций получается монстр.
  2. Агент не видит накопленного долга. Модель оценивает код через призму текущей задачи — «работает ли это сейчас?» Вопрос «будет ли это работать через 10 изменений?» не входит в её целевую функцию.
  3. Тесты не ловят erosion. Eroded код отлично проходит тесты. SlopCodeBench показал: можно снизить erosion вдвое и verbosity на треть — pass rate не изменится. Качество и корректность — ортогональные оси.
  4. Промпты сдвигают intercept, но не slope. Эксперименты с anti-slop промптами («не дублируй код», «избегай избыточных абстракций») снижают начальные verbosity и erosion, но деградация продолжается с той же скоростью.

Практические контрмеры

Если агенты неизбежно деградируют — что с этим делать?

1. Периодический рефакторинг — не опция, а necessity. После каждых 35 итераций агентной разработки запускайте отдельный prompting cycle: «Проведи рефакторинг этого кода. Уменьши erosion и verbosity, не меняя поведение. Разбей функции > 100 строк. Убери дублирование.» Рефакторинг не должен быть частью основного task prompt — он должен быть отдельной фазой с отдельными критериями успеха.

2. CI-гейты на structural quality. Добавьте в CI проверки cyclomatic complexity (например, radon с порогом CC ≤ 10 для новых функций) и duplication detection. Агентский PR с erosion выше порога → автоматический request changes.

3. Лимиты на размер функций/файлов. Жёсткие ограничения: функция ≤ 50 строк, файл ≤ 200 строк (для AI-генерируемого кода). Если агент хочет добавить логику в файл на 199 строк — он обязан сначала отрефакторить.

4. Инварианты и pre/post-conditions как якоря. Когда у функции есть задокументированный инвариант и pre/post-conditions, агенту сложнее «заплаточно» расширять её — он видит, что нарушает контракт. Это не предотвращает erosion полностью, но замедляет.

5. Ротация контекста. Не давайте агенту бесконечно наращивать код в одном контексте. После значительного изменения — закрывайте сессию и начинайте новую со свежим взглядом на код (zero-context survival, §16.3). Это имитирует смену разработчика — свежий взгляд чаще замечает erosion.

6. Human review на структурных маркерах. Настройте автоматическую пометку PR, где: (а) cyclomatic complexity функции выросла > 2×, (б) файл пересёк порог 300 строк, (в) duplication вырос > 10%. Такие PR требуют обязательного человеческого ревью, даже если тесты проходят.

Что это значит для AI-friendly архитектуры

Принципы из предыдущих секций (§16.116.6) — маленькие модули, контракты, явные зависимости — это не просто «хороший стиль». Это структурная защита от erosion. Маленький файл с явным контрактом физически ограничивает, сколько «грязи» может накопить агент за одну итерацию.

SlopCodeBench показал эмпирически: ранние архитектурные решения определяют всю траекторию. Агент, который на C1 захардкодил *.py, создал себе экспоненциально растущий объём работы на C2C5. Агент, который на C1 построил модульную архитектуру — прошёл все чекпоинты с минимальным ростом сложности.

Отсюда правило: первые 12 итерацииAI-генерации — самые важные. Потратьте время на ревью архитектуры на старте, а не на разгребание последствий в конце.


16.8. Конфигурация AI на уровне проекта

Новый стандарт: инструкции для AI рядом с кодом

В 2026 году в корне проекта наряду с .gitignore и README.md появился новый тип файлов — инструкции для AI-агентов. Это не опция; это production-практика, которую используют команды от стартапов до FAANG.

Файл Инструмент Назначение
.cursorrules (или .cursor/rules/ в новых версиях) Cursor Правила для Cursor Agent и автокомплита
.clinerules Cline Инструкции для Cline-агента
AGENTS.md Claude Code Инструкции для Claude Code по папкам и стилю
.github/copilot-instructions.md GitHub Copilot Инструкции для Copilot в VS Code
.windsurfrules Windsurf Правила для Windsurf Cascade

Что писать в этих файлах

Эти файлы — контракт между командой и AI-агентом. Они фиксируют то, что раньше передавалось устно: стиль кода, архитектурные решения, запреты.

# .cursorrules (пример для Python-проекта)

## Стиль кода
- Python 3.12+, type hints обязательны на всех публичных функциях
- Docstrings в формате Google style
- Максимум 100 строк на файл, 30 строк на функцию

## Архитектура
- Бизнес-логика в domain/, HTTP в api/, хранение в storage/
- Никаких глобальных переменных — dependency injection через аргументы
- Каждый модуль имеет свой test_*.py рядом

## Запреты
- НЕ использовать ORM (мы используем raw SQL через asyncpg)
- НЕ добавлять новые зависимости без обсуждения
- НЕ использовать print() — только structlog

## Тестирование
- pytest, тест рядом с модулем
- При изменении функции — обновить тест
# AGENTS.md (пример для Claude Code)

## Общие правила
При изменении любого файла в domain/ — обязательно запустить тесты.

## Структура проекта
- api/ — FastAPI роуты, тонкий слой, без бизнес-логики
- domain/ — чистая бизнес-логика, без зависимостей от фреймворков
- storage/ — работа с БД, все SQL-запросы здесь

## Code review
- Перед коммитом проверь: нет ли файлов > 100 строк
- Все новые функции должны иметь docstring с примером

Почему это работает

AI-агент читает эти файлы первыми — до того, как смотрит ваш код. Это как дать новому сотруднику документ «Как мы здесь работаем» в первый рабочий день. Без него агент будет угадывать ваш стиль (и угадает неправильно). С ним — сразу пишет код по вашим правилам.


16.9. Миграция: от монолита к коду, дружественному ИИ

Пошаговый план рефакторинга

Вы не можете переписать весь проект за день. Но вы можете мигрировать постепенно — и каждый шаг будет давать немедленный эффект для AI-агентов.

Шаг 1: Добавьте конфигурацию AI (1 час). Создайте .cursorrules или AGENTS.md с описанием текущей архитектуры и правил. Это самый быстрый способ улучшить качество AI-генерации — агент сразу поймёт контекст.

Шаг 2: Нарежьте на файлы самые большие модули (12 дня). Найдите файлы > 300 строк: find . -name "*.py" | xargs wc -l | sort -rn | head -20. Разбейте каждый по принципу «один файл = одна концепция». Не меняйте логику — только перемещайте.

Шаг 3: Добавьте контракты к ключевым функциям (постепенно). Начните с публичных функций: type hints + docstring с примером. Не нужно описывать всё сразу — начните с функций, которые AI-агенты меняют чаще всего.

Шаг 4: Переместите тесты к коду (1 день). Вместо tests/test_pricing.pyorder/test_pricing.py. Обновите testpaths в pyproject.toml, чтобы pytest искал тесты прямо в src/.

Шаг 5: Замените implicit globals на аргументы (постепенно). Каждый раз, когда AI-агент (или вы) трогаете функцию с глобальной зависимостью — превращайте её в аргумент. Не нужно менять всё сразу.

Чек-лист миграции

  • .cursorrules / AGENTS.md / copilot-instructions.md создан
  • Нет файлов > 300 строк (find . -name "*.py" | xargs wc -l | sort -rn)
  • Все публичные функции имеют type hints
  • Ключевые функции имеют docstring с примером
  • Тесты рядом с кодом (test_*.py в том же каталоге)
  • Нет глобальных переменных в бизнес-логике
  • README описывает структуру проекта

От недружественного ИИ кода к дружественному: ещё примеры

Пример 1: Неявная конфигурация → явная. Анти-паттерн: import config с обращением к config.SMTP_HOST, config.SMTP_PORT — AI-агент не знает, где этот файл и что в нём. AI-friendly вариант: frozen dataclass SmtpConfig(host, port, user, password) передаётся в send_email() как аргумент. Все зависимости видны в сигнатуре.

Пример 2: Магические строки -> enum'ы. Анти-паттерн: update_order(order, new_status: str) с проверкой if new_status == "paid" — агент не знает полный список статусов. AI-friendly вариант: OrderStatus(str, Enum) с явными членами (PENDING, PAID, SHIPPED, DELIVERED, CANCELLED) и типизированный update_order(order: Order, new_status: OrderStatus) -> Order.

Промпт для генерации кода: «Рефакторинг: есть функция send_email(to, body), которая использует глобальный import config для SMTP-настроек. Перепиши: создай frozen dataclass SmtpConfig (host, port, user, password), передай в send_email как аргумент. Добавь также OrderStatus(str, Enum) с пятью статусами заказа и типизированную update_order.»


Практический вывод

Чек-лист AI-friendly кода

# Правило Метрика
1 Модули < 100 строк wc -l на каждый файл
2 Функции < 30 строк Cyclomatic complexity < 10
3 Явные контракты Типы + docstring + примеры
4 Zero-Context Survival Новичок поймёт без промпта?
5 Линейный > абстрактный WET до 3-х повторений
6 Явные зависимости Через аргументы, не globals
7 Тесты рядом test_*.py в том же каталоге
8 Нет magic numbers Именованные константы
9 AI-конфигурация .cursorrules / AGENTS.md в корне проекта
10 Semantic header на сложных модулях @PURPOSE + @INVARIANT + @RELATION + при необходимости @RATIONALE/@REJECTED
11 Осмысленные имена Файлы и функции названы по смыслу, не utils.py

Ментальная модель

Пишите код не для себя сегодняшнего, а для AI-агента, который увидит его впервые. Если через год Cursor Agent сможет изменить функцию, не сломав соседние — ваша архитектура успешна. Контракты, маленькие модули, явные зависимости и AI-конфигурация в корне проекта — это не теория, а production-практика 2026 года.

Задания

  1. Аудит кодовой базы по размеру файлов. Выполните find . -name "*.py" | xargs wc -l | sort -rn | head -20 в вашем проекте. Файлы > 300 строк — кандидаты на разбиение по принципу «один файл = одна концепция». Ожидаемый результат: список файлов для рефакторинга с приоритизацией по частоте изменений (чем чаще AI-агент касается файла, тем выше приоритет).

  2. Создайте AGENTS.md или .cursorrules для проекта. Опишите: структуру каталогов, стиль кода, архитектурные решения, запреты. Проверьте: попросите AI-агента добавить новый endpoint или функцию — результат должен соответствовать вашим конвенциям без дополнительных инструкций. Ожидаемый результат: файл в корне проекта, который AI-агент читает при первом обращении.

  3. Добавьте контракты к 5 ключевым функциям. Выберите 5 публичных функций, которые AI-агенты изменяют чаще всего (git history → frequency of changes). Добавьте type hints, Google-style docstring с Args/Returns/Raises и Example. Ожидаемый результат: 5 функций с полным контрактом, которые AI-агент может менять с первого раза без ошибок.


Источники

  • Martin, R. C. (2008). "Clean Code: A Handbook of Agile Software Craftsmanship." (Принципы, адаптированные для AI-эры)
  • Fowler, M. (2018). "Refactoring: Improving the Design of Existing Code." 2nd Ed.
  • Cursor. "Rules for AI." Cursor Documentation (20252026).
  • Anthropic. "Best practices for agentic coding." Claude Documentation (2025).
  • Anthropic. "AGENTS.md: A standard for AI agent project configuration." (2026).
  • GitHub. "Copilot coding agent: customization with copilot-instructions.md." GitHub Docs (2026).
  • Cognition. "Devin: AI Software Engineer." Best Practices (20252026).
  • Gan, Z., Ren, R., Yao, W., et al. (2026). "Beyond the Black Box: A Survey on the Theory and Mechanism of Large Language Models." arXiv:2601.02907. Метаобзор по inference-stage практикам: prompt engineering, in-context learning, inference-time scaling и evaluation.
  • Zhao, Z., Wallace, E., Feng, S., Klein, D., & Singh, S. (2021). "Calibrate Before Use: Improving Few-shot Performance of Language Models." ICML 2021. Формат и порядок примеров существенно влияют на качество; полезна калибровка prompt scaffold.
  • Min, S., Lyu, X., Holtzman, A., Artetxe, M., Lewis, M., Hajishirzi, H., & Zettlemoyer, L. (2022). "Rethinking the Role of Demonstrations: What Makes In-Context Learning Work?" EMNLP 2022. В few-shot важны формат, пространство меток и распределение входов, а не только «правильные» ответы в примерах.
  • Khattab, O., Singhvi, A., Maheshwari, P., Zhang, Z., Santhanam, K., Vardhamanan, S., Haq, S., Sharma, A., Joshi, T. T., Moazam, H., Miller, H., Zaharia, M., & Potts, C. (2024). "DSPy: Compiling Declarative Language Model Calls into Self-Improving Pipelines." ICLR 2024 / TMLR. Пайплайны с LLM стоит оптимизировать по метрике, а не править вручную вслепую.
  • Yang, C., Yue, X., Zhang, Y., et al. (2024). "Large Language Models as Optimizers." ICLR 2024. Prompt pipeline можно улучшать итеративно, как оптимизируемый артефакт.
  • Gupta, M., et al. (2026). "Revisiting the Role of Natural Language Code Comments in Code Translation." arXiv:2601.16661.
  • Yang, G., et al. (2026). "Less is more: DocString compression in code generation." ACM TOSEM 35(2). DocString как носитель требований; 2540% compression без потери качества.
  • van Dam, T., Izadi, M., & van Deursen, A. (2023). "Enriching Source Code with Contextual Data for Code Completion Models: An Empirical Study." MSR 2023. Multi-line comments помогают умеренно; не вся дополнительная разметка одинаково полезна.
  • Cheng, W., Wu, Y., & Hu, W. (2024). "Dataflow-Guided Retrieval Augmentation for Repository-Level Code Completion." ACL 2024. Repo-specific context graph и улучшение repository-level completion.
  • Chinthareddy, M. R. (2026). "Reliable Graph-RAG for Codebases: AST-Derived Graphs vs LLM-Extracted Knowledge Graphs." arXiv:2601.08773.
  • Ruan, H., Zhang, Y., & Roychoudhury, A. (2024). "SpecRover: Code Intent Extraction via LLMs." arXiv:2408.02232 / ICSE 2025.
  • Li, Y., et al. (2025). "Your Coding Intent is Secretly in the Context and You Should Deliberately Infer It Before Completion." arXiv:2508.09537.
  • Yao, S., Yu, D., Zhao, J., Shafran, I., Griffiths, T., Cao, Y., & Narasimhan, K. (2023). "Tree of Thoughts: Deliberate Problem Solving with Large Language Models." NeurIPS 2023. Для сложных задач полезен поиск по нескольким траекториям вместо одного ответа.
  • Snell, C., et al. (2025). "Scaling LLM Test-Time Compute Optimally Can Be More Effective Than Scaling Model Parameters." arXiv:2408.03314. Бюджет размышления стоит распределять адаптивно по сложности задачи.
  • Setlur, A., et al. (2025). "Scaling Test-Time Compute Without Verification or RL is Suboptimal." arXiv:2506.14495. Для роста качества нужен verifier, а не просто больше попыток.
  • Swamy, G., et al. (2025). "All Roads Lead to Likelihood: The Value of Reinforcement Learning in Fine-Tuning." arXiv:2505.14864. Генерацию выгодно ограничивать пространством решений, которое хорошо отделяется верификатором.
  • Sprague, Z., et al. (2025). "To CoT or not to CoT? Chain-of-Thought Helps Mainly on Math and Symbolic Reasoning." arXiv:2503.16411. Длинное рассуждение полезно применять выборочно.
  • Wang, X., & Zhou, D. (2024). "Chain-of-Thought Reasoning Without Prompting." arXiv:2402.10200. Не вся полезная reasoning-траектория обязана быть явно выписана в ответе.
  • Ivanov, V. osovv/grace-marketplace README, CHANGELOG v3.53.7, grace-explainer, grace-plan, grace-cli, semantic validator patterns (check_semantics.py) (2026). Shared/public vs file-local/private boundary; schema-aware query layer (module find/show, file show); enforceable semantic markup.
  • Orlanski, G., Roy, D., Yun, A., Ge, A., Adila, D., Shin, C., Gu, A., Sala, F., & Albarghouthi, A. (2026). "SlopCodeBench: Benchmarking How Coding Agents Degrade Over Long-Horizon Iterative Tasks." arXiv:2603.24755.

Навигация: