# Видобування знань з історії змін: як зміни стають інституційною пам'яттю

Canonical source: https://maguyva.ai/uk/blog/mining-workflow-closing-the-loop

License: text under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/); code samples under [MIT-0](https://opensource.org/license/mit-0); the Maguyva name, logos, brand assets and other code are not covered. Details: [maguyva.ai/license](https://maguyva.ai/license).

Date: 2026-02-03 · Author: Maguyva Team

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

> *Числа в цьому дописі відображають стан системи на момент публікації (лютий 2026). Актуальні цифри дивіться на нашій [сторінці команди](/uk/team).*

Кожна інженерна команда стикається з однією й тією самою проблемою: зміни відбуваються постійно, але *причини* цих змін губляться. Через шість місяців хтось запитує «чому ми обрали DuckDB для етапів pipeline?», а відповідь живе лише в голові того, хто ухвалював це рішення — якщо ця людина ще з командою.

Ми побудували робочий процес видобутку (mining), що замикає цей цикл. Зміни проходять через git-коміти, обробляються нашим конвеєром видобутку, перетворюються на структуровані записи журналу змін та архітектурні рішення, а потім повертаються до наших ШІ-агентів через запити CLI. Результат: інституційна пам'ять, доступна і людям, і ШІ.

## Проблема: рішення випаровуються

Розгляньмо типовий сценарій. Розробник комітить:

```
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: Синхронізувати індекс

```bash
uv run orkestra mine sync
```

Ця команда сканує історію git і будує індекс усіх комітів. Вона вилучає структуровані сигнали з кожного коміту:

- Тип коміту за стандартом Conventional Commits (`feat`, `fix`, `chore`, `docs`)
- Область дії (який пакет чи ділянка)
- Маркери зламних змін (breaking change)
- Змінені файли та метрики складності

### Крок 2: Перевірити статус покриття

```bash
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 стали архітектурними рішеннями. 6 799 стали записами журналу змін. Кожен коміт класифіковано.

### Крок 3: Отримати кандидатів для перегляду

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

Це виводить коміти, які ще не оброблено, з повним контекстом для класифікації:

```json
{
  "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: Класифікувати коміти

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

**Для записів журналу змін:**

```bash
uv run orkestra mine classify abc123 --changelog added
```

Це фіксує, що коміт `abc123` має з'явитися в журналі змін під категорією «Added» (Додано).

**Для архітектурних рішень:**

Спочатку отримайте реальний ID рішення:

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

Потім класифікуйте з ID рішення:

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

Це пов'язує коміт із записом рішення, який буде створено чи оновлено.

**Для пакетної обробки (що ми насправді робимо):**

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

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

```jsonl
{"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: Відрендерити вивід

```bash
uv run orkestra registry changelog render --package <pkg>
```

Це генерує файли `CHANGELOG.md` для кожного пакета з журналу (ledger). Журнали змін — похідні артефакти: видаліть їх, і вони бездоганно регенеруються з вихідного журналу.

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

Вилучені рішення стають YAML-файлами з насиченими метаданими:

```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:

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

Повертає рішення про логіку повторних спроб, обробку помилок, патерни відновлення.

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

Повертає повний запис рішення з контекстом, обґрунтуванням та впливом.

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

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

### Як агенти це використовують

Базові інструкції нашого оркестратора включають:

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

Коли агента просять реалізувати щось пов'язане з DuckDB, він може спершу перевірити:

```bash
uv run orkestra registry 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` означає, що кілька агентів можуть класифікувати коміти одночасно без конфліктів злиття. Кожен рядок незалежний.

## Контрольні перевірки

Перед будь-якою сесією видобутку ми запускаємо валідацію:

```bash
uv run orkestra mine validate --quick
```

Це перевіряє:
- Валідність формату SHA
- Відповідність формату ID рішення
- Відсутність дублікатів записів для того самого SHA
- Реальне існування рішень, на які є посилання

Після класифікації ми валідуємо знову перед комітом змін.

## Чому це важливо

Цикл зворотного зв'язку, який ми побудували, вирішує кілька проблем:

**Для нових членів команди:** замість того щоб питати «чому ми зробили X?», вони можуть шукати в реєстрі рішень. Контекст збережено.

**Для ШІ-агентів:** вони не працюють у вакуумі. Вони можуть запитувати інституційні знання перед тим, як давати рекомендації. Коли їх просять додати новий етап pipeline, вони можуть виявити патерн DuckDB і слідувати йому.

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

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

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

## Поточний стан

На сьогодні:
- **15 637 комітів** оброблено через конвеєр
- **476 архітектурних рішень** вилучено й задокументовано
- **6 799 записів журналу змін** зафіксовано
- **100% покриття** в обох доменах

Кожен коміт з моменту, як ми почали, класифіковано. Інституційна пам'ять повна й доступна для запитів.

## Початок роботи

Якщо ви хочете реалізувати щось подібне:

1. **Почніть із комітів за стандартом Conventional Commits.** Конвеєр видобутку працює найкраще, коли коміти мають структуровані префікси (`feat:`, `fix:`, `chore:`).

2. **Визначте свої домени.** Ми використовуємо домени на кшталт `pipeline`, `agent-design`, `observability`, `data-modeling`. Вони організовують рішення за ділянками.

3. **Виробіть звичку класифікації.** Видобуток працює, коли команди регулярно класифікують коміти. Пакетна обробка за допомогою LLM допомагає масштабуватися.

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

5. **Замкніть цикл.** Рішення мають впливати на майбутню роботу. Включайте посилання на рішення в інструкції для агентів та чеклісти перегляду коду.

Мета не в ідеальній документації. Мета в тому, щоб зробити *причини* змін доступними і людям, і ШІ, сьогодні і через шість місяців. Коли зміни стають інституційною пам'яттю, команди спираються на усталені патерни, а не винаходять їх заново.

---

*Робочий процес видобутку — частина нашого рушія оркестрації, зокрема модуля контекстного рушія в нашому пакеті оркестрації.*
