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

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

Содержание

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

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

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

  2. Dogfood CLI и runtime ревью запрашивают CPG по изменённым методам, вычисляют метрики качества, зону поражения, анализ влияния на интерфейсы, межмодульные предупреждения и при необходимости сохраняют состояние ревью в data/reviews/.

  3. Проверки готовности локального контура показывают доступность поддерживающих сервисов. dogfood status сообщает об актуальности CPG, необходимости обслуживания, блокировках и доступности OpenViking в локальной разработке.

Результат: недавние изменения можно оценивать трассируемо и без опоры на локальные git-хуки.

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

Сценарий 1: Ревью после коммита с явным запуском анализа

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

Вы: "Закоммить эти изменения и проанализируй результат"
Claude: git add src/intent/classifier.py && git commit -m "refactor: extract pattern table"
Claude: python -m src.cli.import_commands dogfood analyze --base-ref HEAD~1

Конвейер ревью формирует отчёт:

## 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

**Interface changes detected:**
- **CLI**: `src/cli/intent_commands.py` (`add_intent_commands`, `_run_classify`)

**Cross-module alert** — related interfaces may need updates:
- Changed CLI → check MCP: `codegraph_intent`, `register_intent_tools`

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

Что запускает анализ: явный dogfood analyze, dogfood continue или другой runtime-поток, который вызывает тот же review pipeline.

Что больше не считается основным флоу: фоновые локальные hook-based сценарии.

Сценарий 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"
Claude: python -m src.cli.import_commands dogfood analyze --base-ref HEAD~1
  -> Отчёт ревью показывает: CC 29->8 (-21)

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

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

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

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

Вы: "Продолжай рефакторинг"
Claude: [вносит изменения, коммитит]
Claude: python -m src.cli.import_commands dogfood analyze --base-ref HEAD~1
  -> Отчёт ревью показывает: 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

# Валидация числовых утверждений в документации
python -m src.cli.import_commands dogfood validate-claims --path docs/

# Показать тренд качества по последним коммитам
python -m src.cli.import_commands dogfood trend --commits 20

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

Поток данных

git commit
    |
    v
Явный запуск ревью (`dogfood analyze --base-ref HEAD~1`)
    |
    +-- Проверка актуальности CPG
    |       Запрос cpg_git_state.commit_hash, сравнение с git rev-parse HEAD
    |
    +-- Захват метрик до обновления (для дельта-отчёта)
    |       Запрос nodes_method для изменённых файлов ДО обновления CPG
    |       Сохранение {full_name: {cc, fan_out, ...}} для последующего сравнения
    |
    +-- Обновление CPG если устарел
    |       gocpg update --input=<source> --output=<db>
    |
    +-- Фаза 1: Получение изменённых файлов
    |       git diff --name-only HEAD~1 HEAD, фильтрация по расширениям кода
    |
    +-- Фаза 2: Получение изменённых методов из CPG
    |       Запрос nodes_method для изменённых файлов, дедупликация
    |
    +-- Фаза 3: Сводка качества
    |       Подсчёт high-CC, high-fan_out, TODO, debug, deprecated
    |
    +-- Фаза 4: Зона поражения
    |       Запрос call_containment (или nodes_call в качестве запасного варианта)
    |
    +-- Фаза 5: Обнаружение влияния на интерфейсы
    |       Проверка принадлежности изменённых файлов к слоям интерфейсов (CLI, REST API, MCP, ACP)
    |
    +-- Фаза 6: Межмодульные предупреждения
    |       Поиск связанных функций в ДРУГИХ слоях по совпадению ключевых слов
    |
    +-- Фаза 7: Дельта покрытия историй
    |       Определение изменённых слоёв и непокрытых слоёв
    |
    +-- Запись снимка качества (таблица cpg_quality_history)
    |
    +-- Вывод: {"additionalContext": "## Commit Analysis Report\n..."}
            Внедряется обратно в диалог Claude Code

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

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

Фаза Бюджет Действие
Проверка актуальности Сравнение cpg_git_state.commit_hash с git rev-parse HEAD
Метрики до обновления ~1с Запрос текущих метрик для изменённых файлов (для дельта-отчёта)
Обновление CPG если устарел 40с Запуск gocpg update --input=<source> --output=<db>
Фазы 1–7 ~15с Изменённые файлы, методы, качество, зона поражения, интерфейсы, межмодульные, истории

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

Актуальность CPG и автоматическое обновление

Runtime проверяет актуальность CPG, сравнивая cpg_git_state.commit_hash с git rev-parse HEAD. Если CPG устарел, запускается gocpg update:

gocpg update --input=<source_path> --output=<db_path>

Инфраструктура хуков

Наследуемый код hook/runtime по-прежнему важен как деталь реализации, хотя рекомендуемый рабочий путь теперь строится вокруг явного запуска dogfood analyze и dogfood continue, а не фоновых post-commit hooks.

Ключевые вспомогательные модули в src/dogfooding/hooks/:

  • _feedback.py преобразует результаты конвейера в записи ReviewFinding и ReviewFeedback.
  • _metrics.py предоставляет счётчики hook_metrics и timing helpers для локальной наблюдаемости.
  • _utils.py содержит общие helpers, включая обёртки timed_hook и безопасное форматирование runtime-данных.
  • _session_cache.py управляет состоянием session_cache, которое связывает повторные локальные review runs.

Эти внутренние компоненты важны при диагностике degraded hook behavior, разборе fallback-путей и сравнении текущего explicit runtime с более старыми hook-based экспериментами.

Это запускает инкрементальное обновление базы данных CPG. Класс CPGFreshnessChecker в src/dogfooding/cpg_freshness.py управляет этим процессом:

from src.dogfooding.cpg_freshness import CPGFreshnessChecker

checker = CPGFreshnessChecker(db_path, repo_path=".", gocpg_binary="gocpg/gocpg.exe")
checker.is_fresh()           # True если CPG commit == HEAD
checker.commits_behind()     # Количество коммитов отставания CPG
checker.ensure_fresh(timeout=40.0, source_path=".")  # Обновить если устарел
checker.status()             # Полный словарь статуса

Проверка актуальности теперь включает резервное определение git HEAD для окружений, где git rev-parse HEAD из подпроцесса нестабилен. Проверка читает .git/HEAD, refs и packed-refs (включая gitdir: для worktree) до того, как вернуть head_commit=unknown.

При ошибках блокировки DuckDB возвращается детальная диагностика: классификация сбоя, PID процессов-блокировщиков, результаты попытки auto-unlock и рекомендации next_step / next_command.

Актуальность выводится в двух вариантах: - is_fresh_strict: строгое совпадение коммитов (cpg_commit == head_commit) - is_fresh: эффективная актуальность (строгое совпадение ИЛИ отсутствие CPG-релевантных изменений файлов между коммитами, например при изменениях только документации)

Автоматический и явный контроль актуальности

Механизм Триггер Типичный сценарий
dogfood status Явный/ручной Проверить актуальность, блокировки, обслуживание и готовность OpenViking
dogfood analyze Явный/ручной Запустить ограниченное post-commit или branch-diff ревью
codegraph_watch check / codegraph_watch update Явный/ручной Детерминированная проверка актуальности в headless и CI
CPGFreshnessChecker.ensure_fresh_with_details() Явный/ручной Программный контроль и машиночитаемая диагностика сбоев

Если требуется гарантированная актуальность перед анализом, используйте явный codegraph_watch update или dogfood status, а не устаревшую фоновую автоматизацию.

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

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, затем сравнивает с метриками после обновления. Это создаёт дельту, показывающую реальное влияние изменений:

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

Методы без изменений метрик пропускаются.

Обнаружение влияния на интерфейсы

Анализатор отслеживает 4 слоя интерфейсов, определённых в INTERFACE_LAYERS:

Слой Шаблоны путей Описание
CLI src/cli/ CLI-команды
REST API src/api/routers/ API-эндпоинты
MCP src/mcp/tools/, src/mcp/ MCP-инструменты
ACP src/acp/server/, src/acp/ ACP-обработчики

Когда изменённый файл принадлежит слою интерфейса, отчёт включает секцию «Interface changes detected» со списком затронутых слоёв и методов.

Межмодульные предупреждения

Когда файл в одном слое интерфейса изменяется, анализатор ищет связанные функции в ДРУГИХ слоях, извлекая ключевые слова из имени изменённого файла и запрашивая CPG. Например, при изменении src/cli/reindex_commands.py он ищет функции с “reindex” в имени в MCP, REST API и т.д.

Отчёт включает секцию «Cross-module alert» с рекомендациями по проверке:

**Cross-module alert** — related interfaces may need updates:
- Changed CLI → check MCP: `codegraph_reindex`, `register_reindex_tools`

Дельта покрытия историй

При изменении слоёв интерфейсов анализатор определяет, какие другие слои могут потребовать обновления для поддержания паритета функциональности. Отчёт включает секцию «Story coverage check»:

**Story coverage check** — verify other interfaces:
- CLI changed (`reindex`), check: MCP, REST API, ACP

Проверки рантайма

dogfood status — основной readiness probe для текущего локального workflow. Команда показывает:

  • актуальность CPG и отставание по коммитам
  • необходимость обслуживания DuckDB
  • диагностику блокировок и подсказки по восстановлению
  • состояние сохранённого review trace в data/reviews/
  • доступность OpenViking в локальном контуре

CLI-команды

Все команды доступны через python -m src.cli.import_commands dogfood <подкоманда>.

dogfood status

Проверка актуальности CPG, состояния ревью и готовности локального рантайма:

python -m src.cli.import_commands dogfood status [--db PATH]

dogfood analyze

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

python -m src.cli.import_commands dogfood analyze [--base-ref HEAD~1] [--db PATH]

dogfood report

Генерация отчёта о качестве (markdown или JSON):

python -m src.cli.import_commands dogfood report [--format markdown|json] [--db PATH]

dogfood validate-claims

Валидация числовых утверждений в документации против CPG. Извлекает числа из markdown (например, «95 обработчиков», «12 сценариев») и проверяет через SQL:

python -m src.cli.import_commands dogfood validate-claims [--path PATH] [--db PATH]

Правила валидации определяются в config.yamldogfooding.claims_validation.rules[]. Каждое правило связывает ключевые слова (русские + английские) с SQL-запросом:

claims_validation:
  enabled: true
  timeout: 5.0
  rules:
    - keywords: ["handlers", "обработчиков"]
      sql: "SELECT COUNT(DISTINCT full_name) FROM nodes_method WHERE ..."
      description: "Scenario handler methods"

dogfood trend

Показать тренд качества по последним коммитам из таблицы cpg_quality_history:

python -m src.cli.import_commands dogfood trend [--commits N] [--db PATH]

Выводит ASCII-таблицу с колонками: Commit, Date, Methods, Avg CC, Dead, Hi-CC, TODO.

Снимки качества записываются автоматически после каждого анализа коммита через record_snapshot() в src/dogfooding/quality_history.py.

dogfood validate-stories

Валидация покрытия интерфейсов пользовательскими историями через CPG с использованием StoryValidationRunner:

python -m src.cli.import_commands dogfood validate-stories [--stories 2,8,11] [--path FILE] [--output FILE] [--db PATH] [--go-db PATH]

dogfood config-check

Обнаружение конфигурационных параметров-сирот путём перекрёстной проверки YAML-конфигурации, схемы и использования в коде:

python -m src.cli.import_commands dogfood config-check [--format text|json|csv] [--level error|warning|info|all] [--fix-suggestions] [--config PATH] [--schema PATH] [--source DIR...]
Параметр По умолчанию Описание
--format text Формат вывода: text, json или csv
--level all Минимальный уровень серьёзности для отображения
--fix-suggestions выкл. Показать предложения по исправлению для каждого обнаружения
--config config.yaml Путь к YAML-файлу конфигурации
--schema src/config/unified_config.py Путь к файлу схемы
--source src/ Каталоги для сканирования (можно несколько)

Обнаруживает 6 типов сирот: yaml_unused, yaml_missing, code_orphan, path_mismatch, orphaned_dataclass, unused_default. Использует ConfigOrphanAnalyzer из src/analysis/config_analyzer.py.

dogfood maintain-db

Выполнить плановое обслуживание и очистку CPG-базы:

python -m src.cli.import_commands dogfood maintain-db [--db PATH] [--force] [--json]
Параметр По умолчанию Описание
--db определяется автоматически Путь к базе DuckDB
--force выкл. Продолжить даже при потенциально рискованном состоянии
--json выкл. Вернуть машиночитаемую детализацию обслуживания

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

dogfood continue

Продолжить прерванный сценарий самоанализа из сохранённого состояния ревью:

python -m src.cli.import_commands dogfood continue [--db PATH] [--review-dir PATH] [--json]
Параметр По умолчанию Описание
--db определяется автоматически Путь к базе DuckDB
--review-dir data/reviews Каталог с сохранённым состоянием ревью
--json выкл. Вернуть машиночитаемый результат для автоматизации

Это путь восстановления, когда post-commit review был прерван и нужно продолжить его с последней сохранённой контрольной точки.

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

В 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
  record_quality_history: true   # Записывать QualitySnapshot по каждому коммиту
  quality_history_db_path: data/quality_history.duckdb  # Необязательная отдельная БД для снимков качества
  include_paths:                 # Ограничить самоанализ выбранными корнями исходников
    - src
    - tests
  exclude_paths:                 # Исключить сгенерированный и сторонний код
    - .venv
    - node_modules
  claims_validation:
    enabled: true
    timeout: 5.0                 # Секунды на запрос по каждому утверждению
    rules:                       # Привязки ключевое_слово→SQL для validate-claims
      - keywords: ["handlers", "обработчиков"]
        sql: "SELECT COUNT(...) FROM nodes_method WHERE ..."
        description: "Scenario handler methods"

CommitReport

Датакласс CommitReport (src/dogfooding/commit_analyzer.py) содержит полный результат анализа:

Поле Тип Описание
changed_files List[str] Файлы с кодом, изменённые в коммите
changed_methods List[dict] Методы в изменённых файлах (дедуплицированные)
blast_radius Dict {"callers": {метод: [вызывающие]}, "total_affected": N}
quality_summary Dict Подсчёт high-CC, high-fan_out, TODO, debug, deprecated
interface_impacts List[dict] Затронутые слои интерфейсов (CLI, REST API, MCP, ACP)
cross_module_alerts List[dict] Связанные функции в других слоях интерфейсов
story_coverage_delta List[dict] Пробелы покрытия историй между слоями
is_cpg_fresh bool Был ли CPG актуален
analysis_time_ms int Общее время анализа в миллисекундах
deltas List[dict] Изменения метрик до→после

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

Конвейер ревью возвращает 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

**Interface changes detected:**
- **CLI**: `src/cli/intent_commands.py` (`add_intent_commands`, `_run_classify`)

**Cross-module alert** — related interfaces may need updates:
- Changed CLI → check MCP: `codegraph_intent`, `register_intent_tools`

**Story coverage check** — verify other interfaces:
- CLI changed (`intent`), check: MCP, REST API, ACP

*Analysis completed in 95ms*

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

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

  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. Проверьте локальный runtime: bash python -m src.cli.import_commands dogfood status --db data/projects/my_project.duckdb python -m src.cli.import_commands dogfood analyze --base-ref HEAD~1 --db data/projects/my_project.duckdb

Команды dogfood читают активный проект из 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) - Запустите python -m src.cli.import_commands dogfood status и посмотрите recommended_next_action - Попробуйте ручное обновление: gocpg/gocpg.exe update --input=. --output=<db>

Значения CC равны 0 после инкрементального обновления: - Инкрементальное gocpg update может пропустить MethodMetricsPass для некоторых записей. Новые записи могут иметь cyclomatic_complexity=0. - Логика дедупликации сохраняет запись с наибольшим CC, смягчая эту проблему. - При постоянных проблемах переимпортируйте проект с нуля: python -m src.cli import /path/to/source

Ошибка блокировки DuckDB (“file is being used by another process”): - Другой процесс gocpg.exe запущен (например, от gocpg watch или параллельного refresh). - Runtime использует соединения в режиме только для чтения и обрабатывает ошибки блокировки, переключаясь на запросы через подпроцесс. - codegraph_watch update / ensure_fresh_with_details() возвращают диагностику блокировки (failure_kind=db_lock, locker_pids, auto_unlock_*, next_command) для ускорения восстановления. - Если PID блокировщика совпадает с текущим Python-процессом, auto-unlock преднамеренно не завершает сам себя; выполните предложенный next_command после закрытия блокирующего процесса.

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

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

OpenViking не отображается в статусе: - Поднимите локальный stack и убедитесь, что сервис OpenViking слушает настроенный порт. - Повторно запустите python -m src.cli.import_commands dogfood status и проверьте секцию openviking_status.