Видобуток циклу: як зміни стають інституційною пам'яттю
> Git-коміти перетворюються на структуровані записи журналу змін та архітектурні рішення, а потім повертаються до AI-агентів як інституційна пам'ять, придатна для запитів.
Числа в цьому дописі відображають стан системи на момент публікації (лютий 2026). Актуальні цифри дивіться на нашій сторінці команди.
Кожна інженерна команда стикається з однією й тією самою проблемою: зміни відбуваються постійно, але чому за цими змінами зникає. Через шість місяців хтось запитує «чому ми обрали DuckDB для етапів pipeline?», а відповідь живе лише в голові того, хто ухвалював це рішення — якщо ця людина ще з командою.
Ми побудували робочий процес видобутку (mining), що замикає цей цикл. Зміни проходять через 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 і будує індекс усіх комітів. Вона вилучає структуровані сигнали з кожного коміту:
- Тип конвенційного коміту (
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 стали архітектурними рішеннями. 6 799 стали записами журналу змін. Кожен коміт класифіковано.
Крок 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 має з’явитися в журналі змін під категорією «Added» (Додано).
Для архітектурних рішень:
Спочатку отримайте реальний ID рішення:
uv run orkestra decisions new --domain pipeline --dry-run
# Returns: DEC-PL-143
Потім класифікуйте з ID рішення:
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–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
- Відповідність формату ID рішення
- Відсутність дублікатів записів для того самого SHA
- Реальне існування рішень, на які є посилання
Після класифікації ми валідуємо знову перед комітом змін.
Чому це важливо
Цикл зворотного зв’язку, який ми побудували, вирішує кілька проблем:
Для нових членів команди: замість того щоб питати «чому ми зробили X?», вони можуть шукати в реєстрі рішень. Контекст збережено.
Для AI-агентів: вони не працюють у вакуумі. Вони можуть запитувати інституційні знання перед тим, як давати рекомендації. Коли їх просять додати новий етап pipeline, вони можуть виявити патерн DuckDB і слідувати йому.
Для архітектурної узгодженості: рішення явні й доступні для пошуку. Коли хтось пропонує підхід, що суперечить наявному рішенню, система може виявити конфлікт.
Для генерації журналу змін: нотатки про реліз — не поспіх в останню хвилину. Вони побічний продукт безперервної класифікації під час розробки.
Для онбордингу: нові агенти успадковують повний контекст кодової бази. Вони бачать не лише код — вони бачать рішення, які його сформували.
Поточний стан
На сьогодні:
- 15 637 комітів оброблено через конвеєр
- 476 архітектурних рішень вилучено й задокументовано
- 6 799 записів журналу змін зафіксовано
- 100% покриття в обох доменах
Кожен коміт з моменту, як ми почали, класифіковано. Інституційна пам’ять повна й доступна для запитів.
Початок роботи
Якщо ви хочете реалізувати щось подібне:
-
Почніть з конвенційних комітів. Конвеєр видобутку працює найкраще, коли коміти мають структуровані префікси (
feat:,fix:,chore:). -
Визначте свої домени. Ми використовуємо домени на кшталт
pipeline,agent-design,observability,data-modeling. Вони організовують рішення за ділянками. -
Виробіть звичку класифікації. Видобуток працює, коли команди регулярно класифікують коміти. Пакетна обробка за допомогою LLM допомагає масштабуватися.
-
Зробіть рішення доступними для запитів. Цінність накопичується, коли агенти можуть шукати рішення через CLI. Структуруйте свій вивід для машинного споживання.
-
Замкніть цикл. Рішення мають впливати на майбутню роботу. Включайте посилання на рішення в інструкції для агентів та чеклісти перегляду коду.
Мета не в ідеальній документації. Мета в тому, щоб зробити чому за змінами доступним і людям, і AI, сьогодні і через шість місяців. Коли зміни стають інституційною пам’яттю, команди будують на усталених патернах, а не винаходять їх заново.
Робочий процес видобутку — частина нашого рушія оркестрації, зокрема модуля контекстного рушія в нашому пакеті оркестрації.
Читайте також
Ще з журналу розробки Maguyva
Чому ми оновили пошук коду до voyage-4-large_
Ми перевели наші ембеддинги коду на voyage-4-large — наразі верхівку публічного рейтингу RTEB для пошуку коду. Чесна версія: компроміс, на який ми йдемо, що ми насправді індексуємо, і чому ми платимо за преміум-ембеддинги.
Рекурсивне самовдосконалення мов: шліфування інтелекту коду для ~280 мов_
Ми підтримуємо інтелект коду для ~280 мов. Жодна людина не здатна вручну перевірити це. Тож ми побудували цикл рекурсивного самовдосконалення мов — вибіркова перевірка, LLM як суддя, виправлення одного пункту, повторна валідація — і запускаємо його з флотом ізольованих агентів, доки вилучення не стане справді правильним, а не просто «зеленим».
Мультимодальний пошук зі злиттям: обираємо правильний ретрівер для кожного запиту_
Запит на кшталт «де визначено parseConfig» потребує іншого пошуку, ніж «як працює автентифікація». Maguyva класифікує намір, відповідно зважує чотири режими пошуку і зливає результати за допомогою зваженого Reciprocal Rank Fusion.