Перейти к содержимому
cd /blog

Майнинг цикла: как изменения становятся институциональной памятью

[Архитектура][Рабочие процессы]

> Git-коммиты превращаются в структурированные записи журнала изменений и записи архитектурных решений, а затем возвращаются к AI-агентам в виде запрашиваемой институциональной памяти.

Цифры в этом посте отражают состояние системы на момент публикации (февраль 2026). Актуальные цифры смотрите на нашей странице команды.

Каждая инженерная команда сталкивается с одной и той же проблемой: изменения происходят постоянно, а почему за этими изменениями исчезает. Спустя полгода кто-то спрашивает: «почему мы выбрали DuckDB для этапов пайплайна?» — и ответ живёт только в голове того, кто принял это решение, если этот человек ещё вообще рядом.

Мы построили процесс майнинга, который замыкает этот цикл. Изменения проходят через git-коммиты, обрабатываются нашим конвейером майнинга, становятся структурированными записями журнала изменений и записями архитектурных решений, а затем возвращаются к нашим AI-агентам через запросы CLI. Результат: институциональная память, доступная и людям, и AI.

Проблема: решения испаряются

Рассмотрим типичный сценарий. Разработчик коммитит:

feat(canonical): add DuckDB runtime for pipeline stages

Этот коммит представляет значимый архитектурный выбор. Команда оценила варианты, взвесила компромиссы и остановилась на DuckDB по конкретным причинам. Но весь этот контекст живёт в:

  • Треде в Slack (вероятно, удалённом)
  • Чьей-то памяти (определённо угасающей)
  • Комментарии в коде (может быть, если повезёт)

Спустя три месяца новый участник команды спрашивает: «Стоит ли использовать DuckDB или SQLite для этого нового этапа?» Без институциональной памяти он либо изобретает велосипед заново, либо делает непоследовательный выбор.

Цикл: от коммитов к контексту

Наш процесс майнинга превращает историю git в знание, пригодное для запросов:

Git Commits


┌─────────────────────┐
│  mine sync          │  ← Build index from git history
└─────────────────────┘


┌─────────────────────┐
│  mine candidates    │  ← Surface commits for review
└─────────────────────┘


┌─────────────────────┐
│  Classification     │  ← Human or LLM assessment
│  (changelog or ADR) │
└─────────────────────┘

    ├──────────────────────┐
    ▼                      ▼
┌─────────────┐    ┌───────────────┐
│ Changelog   │    │ Decisions     │
│ Ledger      │    │ Registry      │
│ (JSONL)     │    │ (YAML files)  │
└─────────────┘    └───────────────┘
    │                      │
    ▼                      ▼
┌─────────────┐    ┌───────────────┐
│ CHANGELOG.md│    │ orkestra CLI  │
│ per package │    │ queries       │
└─────────────┘    └───────────────┘
    │                      │
    └──────────────────────┘


      ┌───────────────┐
      │ AI Agents     │
      │ (via CLI)     │
      └───────────────┘

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

Как работает майнинг

Шаг 1: синхронизация индекса

uv run orkestra mine sync

Эта команда сканирует историю git и строит индекс всех коммитов. Она извлекает структурированные сигналы из каждого коммита:

  • Тип conventional-коммита (feat, fix, chore, docs)
  • Область (какой пакет или зона)
  • Маркеры breaking change
  • Затронутые файлы и метрики сложности

Шаг 2: проверка статуса покрытия

uv run orkestra mine status

Вот как выглядит наш текущий статус:

Mining Status
=============

Decisions
---------
  Coverage:        100.0%
    Processed:     15637  (of 15637)
    Extracted:       476
    Skipped:       15161

Changelog
---------
  Coverage:        100.0%
    Processed:     15637  (of 15637)
    Released:       6799
    Skipped:        8838

15 637 коммитов обработано. 476 стали архитектурными решениями. 6799 стали записями журнала изменений. Каждый коммит классифицирован.

Шаг 3: получение кандидатов на ревью

uv run orkestra mine candidates --limit 50 --full

Это выявляет ещё не обработанные коммиты с полным контекстом для классификации:

on
{
  "sha": "90571786d99166c0039ca2e80e4d9cd96184bd85",
  "date": "2026-01-26",
  "subject": "feat(canonical): add DuckDB runtime for pipeline stages",
  "signals": {
    "commit_type": "feat",
    "scope": "canonical",
    "breaking": false,
    "is_releasable_type": true,
    "domains_affected": ["pipeline", "data-architecture"]
  },
  "body": "Establishes DuckDB as canonical in-process analytical database...",
  "files_changed": ["packages/canonical/pipelines/stages/duckdb_runtime.py", "..."],
  "stats": {"files": 8, "insertions": 450, "deletions": 120}
}

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

Шаг 4: классификация коммитов

Здесь пути расходятся: записи журнала изменений и архитектурные решения.

Для записей журнала изменений:

uv run orkestra mine classify abc123 --changelog added

Это фиксирует, что коммит abc123 должен появиться в журнале изменений в категории «Добавлено».

Для архитектурных решений:

Сначала получите настоящий идентификатор решения:

uv run orkestra decisions new --domain pipeline --dry-run
# Returns: DEC-PL-143

Затем классифицируйте с этим идентификатором:

uv run orkestra mine classify abc123 --decision DEC-PL-143

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

Для пакетной обработки (то, что мы реально делаем):

# Generate classifications file with LLM assistance
uv run orkestra mine commit --input classifications.jsonl

Формат JSONL поддерживает оба домена за один проход:

on
l
{"sha":"abc123","domain":"changelog","action":"release","category":"added","summary":"Add DuckDB runtime for pipeline stages"}
{"sha":"abc123","domain":"decisions","action":"extract","decision_id":"DEC-PL-142"}
{"sha":"def456","domain":"changelog","action":"skip","reason":"Chore: dependency update"}

Шаг 5: рендеринг вывода

uv run orkestra changelog render --package <pkg>

Это генерирует файлы CHANGELOG.md для каждого пакета на основе журнала записей (ledger). Журналы изменений — производные артефакты: удалите их, и они идеально восстановятся из исходного журнала записей.

Структура записи решения

Извлечённые решения становятся YAML-файлами с богатыми метаданными:

id: DEC-PL-142
title: Adopt DuckDB as Canonical Processing Runtime for Pipeline Stages
domain: pipeline
status: active
created: '2026-01-26'
summary: |
  Establishes DuckDB as the canonical in-process analytical database for pipeline
  stage transformations. Provides a shared runtime module that resolves settings
  from pipeline defaults with stage-level overrides.

context: |
  Pipeline stages performing data transformations each independently configured
  DuckDB connections. This led to inconsistent settings, duplicated configuration
  code, and no way to tune DuckDB globally for a pipeline run.

rationale:
  - DuckDB provides efficient in-process OLAP with zero configuration deployment
  - Centralized runtime module eliminates duplicated DuckDB setup across stages
  - Hierarchical settings enable global tuning with stage-level overrides
  - Memory limits and thread counts can be adjusted per-pipeline

impact:
  positive:
    - Consistent DuckDB configuration across all pipeline stages
    - Single point of control for memory/thread tuning
    - Reduced code duplication in conversion and export stages
  negative:
    - Adds dependency on shared runtime module
    - Stages must adopt new configuration pattern

source_commits:
  - sha: 90571786d99166c0039ca2e80e4d9cd96184bd85
    message: 'feat(canonical): add DuckDB runtime for pipeline stages'
    date: '2026-01-26'
    role: primary

files:
  - packages/canonical/pipelines/stages/duckdb_runtime.py
  - packages/canonical/pipelines/runner.py
  - packages/canonical/pipelines/stages/convert_hdx_admin_boundaries_to_geoparquet.py

related:
  - DEC-DA-014  # Data architecture decisions that influenced this

Каждое решение ссылается обратно на исходные коммиты. Каждое решение указывает, какие файлы оно затрагивает. Связи между решениями явные.

Интеграция с CLI: запрос институциональной памяти

Вот где цикл замыкается. Агенты могут запрашивать решения через CLI:

# Search by topic
uv run orkestra decisions search --query "retry"

Возвращает решения про логику повторных попыток, обработку ошибок, паттерны восстановления.

# Get full details on a specific decision
uv run orkestra decisions info DEC-PL-142

Возвращает полную запись решения с контекстом, обоснованием и влиянием.

# List recent decisions for context
uv run orkestra decisions list --limit 15

Показывает, какие архитектурные решения были приняты недавно.

Как агенты это используют

Базовые инструкции нашего оркестратора включают:

**Essential CLI commands:**
- `orkestra decisions search "X"` — Find architectural decisions

Когда агента просят реализовать что-то связанное с DuckDB, он может сначала проверить:

uv run orkestra decisions search --query "DuckDB"

И обнаружить DEC-PL-142, узнав:

  • почему мы выбрали DuckDB (context)
  • как использовать его правильно (agent_guidance)
  • какие файлы стоит посмотреть (files)
  • какие связанные решения существуют (related)

Агент не изобретает велосипед заново. Он строит на устоявшихся паттернах.

Тест трёх вопросов

Не каждый коммит заслуживает записи решения. Мы используем Тест трёх вопросов для фильтрации:

  1. Было ли это трудно сделать? Требовало ли это значительного анализа, оценки компромиссов или споров?
  2. Дорого ли это менять? Потребует ли отмена этого решения значительной переделки?
  3. Есть ли у этого влияние на всю систему? Затрагивает ли это несколько пакетов или устанавливает паттерны, которым последуют другие?

Если коммит отвечает «да» хотя бы на один из этих вопросов, он — кандидат на извлечение решения. Наш типичный показатель: 1-4 решения на 100 коммитов (примерно 1-4%).

Для записей журнала изменений планка ниже: любое изменение, видимое пользователю (функции, исправления, улучшения), фиксируется. Внутренние рутинные задачи, обновления документации и рефакторинги обычно пропускаются. Наш типичный показатель: 30-50 записей журнала изменений на 100 коммитов.

Хранение данных: журналы записей только для добавления

Система майнинга использует журналы записей JSONL только для добавления (append-only) для бесконфликтной работы нескольких агентов:

packages/orchestration/ai_assets/reference/changelog/
├── commits_processed.jsonl  # Classification ledger (both domains)
├── release_notes.jsonl      # Changelog entries
└── commits_index.yaml       # Derived index (gitignored)

packages/orchestration/ai_assets/reference/decisions/
├── registry.yaml            # Decision index
└── records/
    ├── DEC-AD-001.yaml
    ├── DEC-AD-002.yaml
    └── ...

Формат JSONL с merge=union в .gitattributes означает, что несколько агентов могут классифицировать коммиты одновременно без конфликтов слияния. Каждая строка независима.

Гейты валидации

Перед каждой сессией майнинга мы запускаем валидацию:

uv run orkestra mine validate --quick

Это проверяет:

  • корректность формата SHA
  • соответствие формату идентификатора решения
  • отсутствие дублирующихся записей для одного и того же SHA
  • реальное существование ссылаемых решений

После классификации мы валидируем снова перед коммитом изменений.

Почему это важно

Построенный нами контур обратной связи решает несколько проблем:

Для новых участников команды: вместо вопроса «почему мы сделали X?» они могут искать в реестре решений. Контекст сохранён.

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

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

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

Для онбординга: новые агенты наследуют полный контекст кодовой базы. Они видят не только код — они видят решения, которые его сформировали.

Текущее состояние

На сегодняшний день:

  • 15 637 коммитов обработано конвейером
  • 476 архитектурных решений извлечено и задокументировано
  • 6799 записей журнала изменений зафиксировано
  • 100% покрытие по обоим доменам

Каждый коммит с момента запуска системы классифицирован. Институциональная память полна и доступна для запросов.

С чего начать

Если вы хотите реализовать нечто подобное:

  1. Начните с conventional-коммитов. Конвейер майнинга работает лучше всего, когда коммиты имеют структурированные префиксы (feat:, fix:, chore:).

  2. Определите свои домены. Мы используем домены вроде pipeline, agent-design, observability, data-modeling. Они организуют решения по областям.

  3. Выработайте привычку классификации. Майнинг работает, когда команды регулярно классифицируют коммиты. Пакетная обработка с помощью LLM помогает масштабироваться.

  4. Сделайте решения доступными для запросов. Ценность растёт, когда агенты могут искать решения через CLI. Структурируйте вывод для машинного потребления.

  5. Замкните цикл. Решения должны влиять на будущую работу. Включайте ссылки на решения в инструкции агентов и чек-листы ревью кода.

Цель — не идеальная документация. Цель — сделать почему за изменениями доступным и людям, и AI, сегодня и спустя полгода. Когда изменения становятся институциональной памятью, команды строят на устоявшихся паттернах, а не изобретают их заново.


Процесс майнинга — часть нашего движка оркестрации, а именно модуля контекстного движка в нашем пакете оркестрации.

Похожие материалы

Ещё из журнала разработки Maguyva

Почему мы обновили поиск по коду до voyage-4-large_

Мы перевели эмбеддинги кода на voyage-4-large — модель, которая сейчас возглавляет публичный рейтинг RTEB по поиску кода. Честная версия: какой компромисс мы принимаем, что мы на самом деле индексируем и почему платим за премиальные эмбеддинги.

[Эмбеддинги][Поиск][Архитектура]

Рекурсивное самосовершенствование языков: шлифуем интеллектуальный анализ кода на ~280 языках_

Мы поддерживаем интеллектуальный анализ кода для ~280 языков. Ни один человек не может вручную проверить это. Поэтому мы построили цикл рекурсивного самосовершенствования языков — выборочная проверка, LLM в роли судьи, исправление одной вещи, повторная валидация — и прогоняем его флотом изолированных агентов, пока извлечение не станет по-настоящему верным, а не просто «зелёным».

[Архитектура][Языки][Агенты]

Мультимодальный фьюжн-поиск: выбор правильного ретривера для каждого запроса_

Запрос вроде «где определён parseConfig» требует другого поиска, чем «как работает аутентификация». Maguyva классифицирует намерение, соответствующим образом взвешивает четыре модальности поиска и сливает результаты с помощью взвешенного Reciprocal Rank Fusion.

[Поиск][Архитектура]