Руководство по самоанализу: анализ коммитов на базе CPG

Руководство по самоанализу: анализ коммитов на базе CPG

CodeGraph анализирует собственную кодовую базу через граф свойств кода (CPG) после каждого коммита, создавая цикл обратной связи Планирование-Действие-Проверка. Claude Code получает метрики качества, данные о зоне поражения и сравнение до/после как контекст сразу после коммита.

Содержание

Как это работает

Конвейер самоанализа связывает три системы:

  1. GoCPG строит и поддерживает граф свойств кода (CPG) в DuckDB с предвычисленными метриками для каждого метода: цикломатическая сложность, входящая/исходящая связность, флаги TODO/FIXME, отладочный код, устаревшие вызовы.

  2. Git-хуки запускают обновление CPG после каждого коммита, поддерживая базу данных в синхронизации с кодом.

  3. Хуки Claude Code срабатывают после команд git commit, запрашивают CPG по изменённым методам, вычисляют метрики качества и зону поражения, затем внедряют отчёт обратно в диалог как дополнительный контекст.

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

Сценарии использования

Сценарий 1: Автоматическая обратная связь после коммита

Основной сценарий. Вы работаете в Claude Code, вносите изменения, коммитите:

Вы: "Закоммить эти изменения"
Claude: git add src/intent/classifier.py && git commit -m "refactor: extract pattern table"

Хук PostToolUse срабатывает автоматически и внедряет отчёт:

## Commit Analysis Report
**Summary:** 1 files, 45 methods, 2 high-CC, 3 TODO/FIXME, 128 affected callers
**CPG status:** fresh

**Impact of changes:**
- `_get_fallback_domain`: CC 29->8 (-21), FanOut 18->5 (-13)

**High complexity methods:**
- `classify` (CC: 17)
- `_score_domain` (CC: 16)

**Blast radius:** 128 callers affected
- `classify` called by: `run_intent_classifier`, `IntentBenchmark._evaluate_single` +126 more

Claude видит этот контекст и может отреагировать: “Рефакторинг снизил сложность _get_fallback_domain с 29 до 8. Два метода всё ещё имеют CC>10: classify и _score_domain.”

Что запускает хук: Любая команда git commit, выполненная через инструмент Bash. Хук обнаруживает "git commit" в строке команды. Другие Bash-команды (git status, ls) игнорируются.

Что НЕ запускает хук: Прямые коммиты из терминала вне Claude Code, git commit --amend, коммиты через другие инструменты.

Сценарий 2: Поиск и исправление проблем качества

Используйте CPG-запросы для поиска целей по улучшению качества, затем исправляйте их с обратной связью от конвейера:

Вы: "Запроси CPG для методов с CC > 15 и флагами TODO/FIXME в src/workflow/"
Claude: [выполняет запрос к DuckDB]
  Найдено: _get_fallback_domain (CC=29, TODO), PolicyViolationsHandler.handle (CC=68, TODO)

Вы: "Отрефактори _get_fallback_domain для снижения сложности"
Claude: [извлекает шаблоны в таблицу данных, заменяет цепочку if/else на цикл]

Вы: "Закоммить"
Claude: git commit -m "refactor: extract fallback patterns to class-level table"
  -> Хук срабатывает, отчёт показывает: CC 29->8 (-21)

Это полный цикл Планирование-Действие-Проверка: 1. Планирование: CPG-запрос выявляет проблему 2. Действие: Рефакторинг снижает сложность 3. Проверка: Хук подтверждает улучшение конкретными метриками

Сценарий 3: Валидация влияния рефакторинга

Перед крупным рефакторингом проверьте зону поражения:

Вы: "Какова зона поражения при изменении HierarchicalIntentClassifier.classify?"
Claude: [запрашивает call_containment]
  213 прямых вызывающих методов в рабочем коде и тестах

Вы: "Продолжай рефакторинг"
Claude: [вносит изменения, коммитит]
  -> Хук показывает: 213 затронутых вызывающих, CC без изменений, регрессий нет

Отчёт о зоне поражения помогает оценить риск изменений до их применения.

Сценарий 4: Анализ по запросу

Запуск анализа без коммита:

# Анализ последнего коммита
python -m src.cli.import_commands dogfood analyze --base-ref HEAD~1

# Анализ изменений между ветками
python -m src.cli.import_commands dogfood analyze --base-ref origin/main

# Генерация полного отчёта о качестве
python -m src.cli.import_commands dogfood report --format markdown

Архитектура конвейера

Поток данных

git commit (через инструмент Bash в Claude Code)
    |
    v
Хук PostToolUse срабатывает (.claude/hooks/commit_analysis.py, время ожидания 60с)
    |
    +-- Фаза 1: Проверка актуальности CPG
    |       Запрос cpg_git_state.commit_hash, сравнение с git rev-parse HEAD
    |
    +-- Фаза 1.5: Захват метрик до обновления (для дельта-отчёта)
    |       Запрос nodes_method для изменённых файлов ДО обновления CPG
    |       Сохранение {full_name: {cc, fan_out, ...}} для последующего сравнения
    |
    +-- Фаза 2: Обновление CPG (--force для точных метрик)
    |       gocpg update --force --input=<source> --output=<db>
    |       Полный перепарсинг гарантирует вычисление CC/fan_in/fan_out через MethodMetricsPass
    |
    +-- Фаза 3: Анализ качества + зона поражения
    |       Запрос nodes_method для изменённых файлов (после обновления)
    |       Дедупликация методов (нормализация слешей, выбор наибольшего CC)
    |       Сводка качества: high-CC, high-fan_out, TODO, debug, deprecated
    |       Запрос call_containment для вызывающих изменённых методов
    |
    +-- Фаза 4: Вычисление дельты
    |       Сравнение метрик до и после обновления
    |       Генерация отчёта до->после: "CC 29->8 (-21)"
    |
    +-- Вывод: {"additionalContext": "## Commit Analysis Report\n..."}
            Внедряется обратно в диалог Claude Code

Бюджет ограничений по времени

Хук имеет общее ограничение по времени 60 секунд с внутренними фазами:

Фаза Бюджет Действие
Проверка актуальности Сравнение cpg_git_state.commit_hash с git rev-parse HEAD
Метрики до обновления ~1с Запрос текущих метрик для изменённых файлов (для дельта-отчёта)
Обновление CPG (–force) 40с Запуск gocpg update --force для полного перепарсинга с метриками
Анализ качества Запрос nodes_method для CC, TODO, debug, deprecated
Зона поражения Запрос call_containment для прямых вызывающих

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

Актуальность CPG и полный перепарсинг

Хук использует флаг --force при запуске gocpg update. Это запускает полный перепарсинг вместо инкрементального обновления. Причина:

  • Инкрементальное обновление (gocpg update без --force): Создаёт новые записи методов, но пропускает MethodMetricsPass. Новые записи имеют cyclomatic_complexity=0, fan_in=0, fan_out=0. Быстро, но метрики неполные.

  • Полный перепарсинг (gocpg update --force): Запускает полный конвейер парсинга включая MethodMetricsPass. Все метрики вычисляются корректно. Медленнее, но точно.

Для самоанализа точность важнее скорости. Бюджет в 40 секунд достаточен для полного перепарсинга проектов до нескольких сотен исходных файлов.

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

GoCPG может хранить один и тот же метод с разными форматами имени файла (прямой слеш src/file.py vs обратный src\file.py). Анализатор дедуплицирует путём нормализации слешей в full_name и сохранения записи с наибольшим значением CC:

# До дедупликации: 2 записи для одного метода
src\intent\classifier.py:Classifier.classify  CC=17
src/intent/classifier.py:Classifier.classify   CC=0  (из инкрементального обновления)

# После дедупликации: 1 запись, наибольший CC побеждает
src\intent\classifier.py:Classifier.classify  CC=17

Дельта-отчёт

Когда CPG устарел (требует обновления), хук захватывает метрики до обновления перед запуском gocpg update --force, затем сравнивает с метриками после обновления. Это создаёт дельту, показывающую реальное влияние изменений:

**Impact of changes:**
- `_get_fallback_domain`: CC 29->8 (-21), FanOut 18->5 (-13)
- `_build_quality_summary`: CC 5->3 (-2)

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

Установка

Установка одной командой

python -m src.cli.import_commands dogfood setup --repo . --db data/projects/codegraph.duckdb

Это устанавливает git-хуки (через gocpg) и проверяет конфигурацию хуков Claude Code.

Ручная установка

  1. Установка git-хуков (фоновое обновление CPG при коммите): bash gocpg/gocpg.exe hooks install --repo=. --db=data/projects/codegraph.duckdb

  2. Настройка хуков Claude Code в .claude/settings.json: json { "hooks": { "PostToolUse": [{ "matcher": "Bash", "hooks": [{ "type": "command", "command": "python .claude/hooks/commit_analysis.py", "timeout": 60000 }] }] } }

Примечание: Поле matcher должно быть строкой (регулярное выражение), а не объектом. "Bash" соответствует конкретно инструменту Bash.

Проверка установки

python -m src.cli.import_commands dogfood status

Ожидаемый вывод показывает актуальность CPG, статус хуков и путь к базе данных.

CLI-команды

# Полная установка (git-хуки + хуки Claude Code)
python -m src.cli.import_commands dogfood setup [--repo PATH] [--db PATH] [--language LANG]

# Проверка актуальности CPG и статуса хуков
python -m src.cli.import_commands dogfood status [--db PATH]

# Запуск анализа коммита по запросу
python -m src.cli.import_commands dogfood analyze [--base-ref HEAD~1] [--db PATH]

# Генерация отчёта о качестве (markdown или JSON)
python -m src.cli.import_commands dogfood report [--format markdown|json] [--db PATH]

Конфигурация

В config.yaml:

dogfooding:
  enabled: true
  auto_update_cpg: true          # Запускать gocpg update если CPG устарел
  cpg_update_timeout: 40         # Секунды на обновление CPG
  analysis_timeout: 16           # Секунды на анализ качества + зону поражения
  cc_threshold: 10               # Отмечать методы с CC выше этого значения
  fan_out_threshold: 30          # Отмечать методы с fan_out выше этого значения
  blast_radius_depth: 2          # Максимальная глубина обхода вызывающих
  max_files_per_commit: 15       # Максимум файлов для анализа за коммит
  report_format: markdown        # markdown или json

Формат отчёта

Хук возвращает markdown-отчёт как additionalContext в JSON:

{"additionalContext": "## Commit Analysis Report\n**Summary:** ..."}

Полная структура отчёта:

## Commit Analysis Report
**Summary:** 3 files, 45 methods, 2 high-CC, 1 TODO/FIXME, 128 affected callers
**CPG status:** fresh

**Impact of changes:**
- `_get_fallback_domain`: CC 29->8 (-21), FanOut 18->5 (-13)

**High complexity methods:**
- `classify` (CC: 17)
- `_score_domain` (CC: 16)

**High fan-out methods:**
- `classify` (fan_out: 39)

**Blast radius:** 128 callers affected
- `classify` called by: `run_intent_classifier`, `IntentBenchmark._evaluate_single` +126 more
- `_classify_domain` called by: `classify`, `get_morph` +4 more

*Analysis completed in 95ms*

Секции пропускаются если пустые (нет high-CC методов = нет секции “High complexity”).

Масштабирование на другие проекты

Конвейер самоанализа не привязан к конкретному проекту. Для настройки на любой проект:

  1. Импортируйте проект для создания базы данных CPG: bash python -m src.cli import /path/to/project --language python

  2. Зарегистрируйте проект в config.yaml: yaml projects: active: my_project registry: my_project: db_path: data/projects/my_project.duckdb source_path: /path/to/project language: python domain: python_generic

  3. Запустите установку: bash python -m src.cli.import_commands dogfood setup --repo /path/to/project --db data/projects/my_project.duckdb

Хук читает активный проект из config.yaml и автоматически определяет правильный путь к базе данных.

Устранение неполадок

Хук возвращает пустой {}: - Проверьте, что файл базы данных существует по настроенному db_path - Убедитесь, что активный проект в config.yaml имеет валидный db_path - Запустите python -m src.cli.import_commands dogfood status для проверки актуальности - Убедитесь, что коммит изменил файлы с кодом (.py, .go, .c и т.д.), а не только документацию или конфигурации

CPG всегда показывает устаревший статус: - Убедитесь, что бинарник gocpg существует по пути gocpg/gocpg.exe (или настроенному GOCPG_PATH) - Проверьте, что git-хуки установлены: ищите .git/hooks/post-commit - Попробуйте ручное обновление: gocpg/gocpg.exe update --force --input=. --output=<db>

Значения CC равны 0 после инкрементального обновления: - Это происходит когда gocpg update запускается без --force. Инкрементальное обновление пропускает MethodMetricsPass. - Хук использует --force по умолчанию. Если вы видите CC=0, полный перепарсинг мог превысить ограничение по времени. Проверьте бюджет в 40 с.

Ошибка блокировки DuckDB (“file is being used by another process”): - Другой процесс gocpg.exe запущен (например, от gocpg watch или параллельного вызова хука). - Хук использует соединения в режиме только для чтения и обрабатывает ошибки блокировки, переключаясь на запросы через подпроцесс.

Дельта-отчёт не появляется: - Дельта-отчёт появляется только когда CPG был устаревшим до обновления (были захвачены метрики до обновления). - Если CPG уже актуален (например, gocpg watch обновил его), метрики до обновления отсутствуют для сравнения.

Превышение времени ожидания: - Бюджет в 60 с достаточен для большинства коммитов. Для очень больших проектов gocpg update --force может превысить бюджет фазы в 40 с. - Уменьшите max_files_per_commit в конфигурации или рассмотрите использование инкрементального обновления (уберите force=True в commit_analysis.py). - Убедитесь, что индексы GoCPG актуальны: gocpg/gocpg.exe index --db=<db>