Перейти к содержанию
Публикация AiManual

Контекст проекта в репозитории, а не в чате: как устроены методика GRACE и утилита doubled-graph

Разбираем методику GRACE (лицензия MIT, автор osovv) и утилиту doubled-graph: пять context-файлов, якоря MODULE_CONTRACT и CONTRACT, два графа, detect_changes,

Коротко

Что будет в материале

  1. 01

    Почему контекст в чате не решает проблему

  2. 02

    Что такое GRACE: замысел, границы и проверки рядом с кодом

  3. 03

    Разметка кода якорями: MODULE_CONTRACT, CONTRACT, MODULE_MAP и LINKS

  4. 04

    Два графа: declared по замыслу и computed по AST

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

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

Альтернатива из статьи: методика GRACE (лицензия MIT, автор osovv), где замысел, границы модулей и проверки лежат рядом с кодом, плюс надстройка doubled-graph со сценарием миграции, графом вызовов через CodeGraphContext и MCP-обёрткой. Ниже механика, пример разметки и трезвая оценка ограничений.

Почему контекст в чате не решает проблему

Разговор и решение: это не одно и то же

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

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

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

Налог на каждую новую сессию

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

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

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

Что такое GRACE: замысел, границы и проверки рядом с кодом

Методику сделал osovv, распространяется она под лицензией MIT. Идея простая: замысел, границы модулей и проверки лежат в репозитории рядом с кодом. Не в голове разработчика и не в архиве диалога, а в файлах, которые версионируются вместе с исходниками.

Пять context-файлов, граф модулей, записи проверок и бандлы изменений

  • Пять context-файлов фиксируют замысел и рамки проекта в нормативном виде: агент читает постановку, а не переписку о постановке.
  • Граф модулей описывает связи и зависимости между модулями, по нему видно, что от чего зависит и что затронет правка.
  • Записи проверок отвечают на вопрос, чем подтверждена работоспособность модуля.
  • Бандлы изменений фиксируют, что именно менялось в рамках правки.

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

Чем это отличается от README и ADR

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

Разметка кода якорями: MODULE_CONTRACT, CONTRACT, MODULE_MAP и LINKS

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

Пример контракта модуля и функции

// START_MODULE_CONTRACT
// PURPOSE: validate JWT and resolve User
// SCOPE: src/auth/validate.ts
// DEPENDS: M-AUTH-TOKENS
// LINKS: M-AUTH-VALIDATE
// ROLE: RUNTIME
// MAP_MODE: EXPORTS
// END_MODULE_CONTRACT

// START_CONTRACT: validateUser
// PURPOSE: validate JWT, resolve user
// INPUTS: req: Request (with Authorization: Bearer header)
// OUTPUTS: User | null (null if invalid, never throws)
// SIDE_EFFECTS: none
// END_CONTRACT: validateUser

Поля контракта модуля отвечают за разные вещи. PURPOSE описывает назначение, SCOPE привязывает запись к файлу src/auth/validate.ts, DEPENDS указывает зависимость от модуля токенов M-AUTH-TOKENS, LINKS связывает файл с модулем M-AUTH-VALIDATE, ROLE задаёт роль в рантайме, MAP_MODE определяет, что попадёт в карту модуля (в примере EXPORTS).

Поле CONTRACTЧто фиксируетЗначение в примере
PURPOSEЗачем существует функцияvalidate JWT, resolve user
INPUTSВходные данные и их формаreq: Request с заголовком Authorization: Bearer
OUTPUTSЧто возвращается и при каких условияхUser | null, null при невалидном токене, исключение не бросает
SIDE_EFFECTSПобочные эффектыnone

Два последних поля дают проверяемые утверждения. «Never throws» и «side effects: none» можно подтвердить или опровергнуть тестом, а расхождение с кодом видно на ревью без чтения всей функции. Внутри тела функции в примере размечаются ещё и блоки: START_BLOCK_DECODE_JWT и END_BLOCK_DECODE_JWT для декодирования токена, START_BLOCK_CHECK_CLOCK_SKEW и END_BLOCK_CHECK_CLOCK_SKEW для проверки расхождения часов.

LINKS решает задачу навигации: поле связывает файл с модулем, чтобы при grep модель могла определить принадлежность файла модулю. Без такой привязки поиск по коду даёт список путей без контекста. MODULE_MAP и поле MAP_MODE в примере задают, что попадает в карту модуля; формат самой карты в разобранном фрагменте не детализирован.

Что проверяет линтер якорей

  • Парность. У каждого START есть соответствующий END. Незакрытый блок означает, что границы контракта в файле не определены.
  • Уникальность. Идентификаторы якорей не дублируются, иначе два разных места кода претендуют на одну запись замысла.
  • Соответствие экспортам. Якорь ссылается на реально существующий экспорт, а не на функцию, которую переименовали три месяца назад.

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

Два графа: declared по замыслу и computed по AST

Утилита строит два графа. Declared собирается по замыслу: из разметки якорями и context-файлов. Computed строится по AST, то есть по фактическому коду. Расхождение между графами и есть предмет работы детектора. Формат графов и алгоритм сверки в разобранном фрагменте статьи не раскрыты, это внутренняя механика утилиты.

Похожую задачу решают локальные анализаторы кода, но с другим акцентом. repopedia парсит код через tree-sitter и складывает граф в SQLite, отвечая на вопрос, как устроен код. TeaRAGs добавляет к графу вызовов семантический поиск и git-метрики. GRACE работает иначе: он сверяет фактический код с заявленным замыслом, а не только описывает структуру.

Детектор дрейфа detect_changes и типы расхождений

  • code_without_module. Код есть, а модуля в замысле нет. Типичный случай: файл или функцию добавили мимо разметки, и в declared-графе они не отражены.
  • missing_verification. У модуля нет записи проверки. Формально код на месте, но подтверждения работоспособности нет.

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

doubled-graph: что автор добавил к GRACE

К upstream-методике автор добавил три вещи, которых там не было: сценарий миграции существующего кода, граф вызовов через CodeGraphContext и MCP-обёртку. Всё вместе называется doubled-graph. По словам автора, он использует её полгода; это личный опыт, а не результат измерений.

Граф вызовов через CodeGraphContext

Граф вызовов показывает связи между функциями, тогда как declared и computed работают на уровне модулей. Разница ощутима при правке: изменение в одной функции задевает вызывающих, и это видно до запуска тестов. Интеграция с CodeGraphContext - добавление автора, в upstream GRACE такого слоя не было. Детали реализации в разобранном фрагменте не описаны.

MCP-обёртка: контекст как инструмент агента

MCP-обёртка отдаёт контекст агенту как инструмент. Агент запрашивает нужное через MCP: контракт модуля, связи, записи проверок. Пересказывать структуру проекта в промпте и надеяться, что агент запомнит, больше не нужно.

Смежную задачу решает Later Bender, отдельный слой состояния проекта с задачами, заметками и runbook'ами, к которому подключаются разные модели через MCP. Там состояние живёт в сервисе, в doubled-graph контекст остаётся в репозитории рядом с кодом. Детали реализации MCP-обёртки в разобранном фрагменте не раскрыты.

Режимы migration и post_migration: как перевести существующий код на GRACE

Для проектов, которые уже написаны, есть режим migration: приведение существующего кода к разметке якорями и построение графов. Режим post_migration включается после: это работа в уже размеченном репозитории, где дальше поддерживают якоря, графы и записи проверок.

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

Установка через pipx и готовые промпты

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

Десять обязательных принципов методики

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

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

Ограничения подхода и как проверить его на своём проекте

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

Кому подход вряд ли окупится

  • Одноразовые скрипты и прототипы на пару дней. Разметка якорями, context-файлы и графы стоят дороже, чем сам код, который никто не будет сопровождать.
  • Проекты без повторяющихся сессий. Если агент заходит в код один раз, налог на восстановление контекста платить не приходится, и выгода исчезает.
  • Работа без AI-агента в цикле. Ценность разметки в том, что её читает модель; при полностью ручной разработке часть артефактов превращается в формальность.
  • Команды без дисциплины поддержки. Если якоря и записи проверок не обновляют вместе с кодом, detect_changes начнёт выдавать расхождения пачками, и его перестанут читать.

Цена подхода складывается из разметки каждого модуля, ведения context-файлов, записей проверок и бандлов, а также поддержки графов и линтера. Это аргументированная оценка, а не измеренная цифра.

Тест на переносимость контекста

  1. Возьмите агента, который проект никогда не видел: другая модель, пустой чат, без истории и без подсказок.
  2. Дайте ровно один промпт: «прочитай, что здесь есть, и расскажи, как устроен проект и что в нём сейчас происходит».
  3. Сверьте ответ с реальным устройством проекта: границы модулей, зависимости, что сейчас в работе.
  4. Повторите то же на репозитории, где контекст живёт только в переписке, и сравните ответы.

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

Подписаться на канал