Wydobywanie pętli: jak zmiany stają się pamięcią instytucjonalną
> Commity git stają się ustrukturyzowanymi wpisami changeloga i rekordami decyzji architektonicznych, a następnie wracają do agentów AI jako przeszukiwalna pamięć instytucjonalna.
Liczby w tym wpisie odzwierciedlają system w momencie publikacji (luty 2026). Aktualne dane znajdziesz na naszej stronie zespołu.
Każdy zespół inżynieryjny mierzy się z tym samym wyzwaniem: zmiany zachodzą nieustannie, ale powód tych zmian znika. Sześć miesięcy później ktoś pyta „dlaczego przyjęliśmy DuckDB dla etapów pipeline’u?”, a odpowiedź żyje tylko w głowie osoby, która podjęła tę decyzję — jeśli w ogóle jeszcze tu jest.
Zbudowaliśmy przepływ pracy wydobywczy (mining), który zamyka tę pętlę. Zmiany przepływają przez commity git, są przetwarzane przez nasz pipeline wydobywczy, stają się ustrukturyzowanymi wpisami changeloga i rekordami decyzji architektonicznych, a następnie wracają do naszych agentów AI przez zapytania CLI. Wynik: pamięć instytucjonalna, do której mają dostęp zarówno ludzie, jak i AI.
Problem: decyzje wyparowują
Rozważ typowy scenariusz. Deweloper commituje:
feat(canonical): add DuckDB runtime for pipeline stages
Ten commit reprezentuje istotny wybór architektoniczny. Zespół ocenił opcje, rozważył kompromisy i wylądował na DuckDB z konkretnych powodów. Ale cały ten kontekst żyje w:
- Wątku na Slacku (prawdopodobnie usuniętym)
- Pamięci kogoś (zdecydowanie blaknącej)
- Komentarzu w kodzie (może, jeśli masz szczęście)
Trzy miesiące później nowy członek zespołu pyta: „Powinienem użyć DuckDB czy SQLite dla tego nowego etapu?”. Bez pamięci instytucjonalnej albo wymyślają koło na nowo, albo dokonują niespójnych wyborów.
Pętla: od commitów do kontekstu
Nasz przepływ pracy wydobywczy zamienia historię git w przeszukiwalną wiedzę:
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) │
└───────────────┘
Kluczowa obserwacja: zarówno changelogi, jak i decyzje architektoniczne wypływają z tej samej historii git, przetwarzanej przez ujednolicony pipeline. To zapewnia, że nic nie umknie.
Jak działa wydobywanie
Krok 1: Synchronizacja indeksu
uv run orkestra mine sync
To polecenie skanuje historię git i buduje indeks wszystkich commitów. Wyodrębnia ustrukturyzowane sygnały z każdego commita:
- Typ zgodny z konwencją commitów (
feat,fix,chore,docs) - Zakres (który pakiet lub obszar)
- Znaczniki zmian łamiących kompatybilność
- Dotknięte pliki i metryki złożoności
Krok 2: Sprawdzenie statusu pokrycia
uv run orkestra mine status
Oto jak wygląda nasz obecny 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 przetworzonych commitów. 476 stało się decyzjami architektonicznymi. 6799 stało się wpisami changeloga. Każdy commit sklasyfikowany.
Krok 3: Uzyskanie kandydatów do przeglądu
uv run orkestra mine candidates --limit 50 --full
To wydobywa commity, które nie zostały jeszcze przetworzone, wraz z pełnym kontekstem do klasyfikacji:
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}
}
Sygnały pomagają w klasyfikacji: is_releasable_type: true sugeruje, że powinno się to znaleźć w changelogu. Duża liczba wstawień i pliki infrastrukturalne sugerują, że może to być też decyzja architektoniczna.
Krok 4: Klasyfikacja commitów
W tym miejscu rozchodzą się dwie ścieżki: wpisy changeloga i decyzje architektoniczne.
Dla wpisów changeloga:
uv run orkestra mine classify abc123 --changelog added
To zapisuje, że commit abc123 powinien pojawić się w changelogu w kategorii „Dodano”.
Dla decyzji architektonicznych:
Najpierw uzyskaj prawdziwy identyfikator decyzji:
uv run orkestra decisions new --domain pipeline --dry-run
# Returns: DEC-PL-143
Następnie klasyfikuj z identyfikatorem decyzji:
uv run orkestra mine classify abc123 --decision DEC-PL-143
To łączy commit z rekordem decyzji, który zostanie utworzony lub zaktualizowany.
Do przetwarzania wsadowego (co faktycznie robimy):
# Generate classifications file with LLM assistance
uv run orkestra mine commit --input classifications.jsonl
Format JSONL obsługuje obie domeny w jednym przebiegu:
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"}
Krok 5: Renderowanie wyników
uv run orkestra changelog render --package <pkg>
To generuje pliki CHANGELOG.md dla poszczególnych pakietów na podstawie ledgera. Changelogi są artefaktami pochodnymi — usuń je, a wygenerują się na nowo idealnie z ledgera źródłowego.
Struktura rekordu decyzji
Wyodrębnione decyzje stają się plikami YAML z bogatymi metadanymi:
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
Każda decyzja odsyła z powrotem do swoich commitów źródłowych. Każda decyzja określa, których plików dotyczy. Relacje między decyzjami są jednoznaczne.
Integracja CLI: odpytywanie pamięci instytucjonalnej
Tu właśnie zamyka się pętla. Agenci mogą odpytywać decyzje przez CLI:
# Search by topic
uv run orkestra decisions search --query "retry"
Zwraca decyzje dotyczące logiki ponawiania, obsługi błędów, wzorców odzyskiwania.
# Get full details on a specific decision
uv run orkestra decisions info DEC-PL-142
Zwraca kompletny rekord decyzji z kontekstem, uzasadnieniem i wpływem.
# List recent decisions for context
uv run orkestra decisions list --limit 15
Pokazuje, jakie wybory architektoniczne zostały podjęte ostatnio.
Jak agenci tego używają
Bazowe instrukcje naszego orkiestratora zawierają:
**Essential CLI commands:**
- `orkestra decisions search "X"` — Find architectural decisions
Gdy agent zostaje poproszony o zaimplementowanie czegoś związanego z DuckDB, może najpierw sprawdzić:
uv run orkestra decisions search --query "DuckDB"
I odkryć DEC-PL-142, dowiadując się:
- Dlaczego wybraliśmy DuckDB (kontekst)
- Jak używać go poprawnie (agent_guidance)
- Na które pliki spojrzeć (files)
- Jakie powiązane decyzje istnieją (related)
Agent nie wymyśla koła na nowo. Buduje na ustalonych wzorcach.
Test trzech pytań
Nie każdy commit zasługuje na rekord decyzji. Używamy testu trzech pytań, aby filtrować:
- Czy to było trudne do podjęcia? Czy wymagało znaczącej analizy, oceny kompromisów lub debaty?
- Czy kosztowna jest zmiana tego? Czy cofnięcie tej decyzji wymagałoby znacznego nakładu pracy?
- Czy ma wpływ na cały system? Czy wpływa na wiele pakietów lub ustanawia wzorce, które inni będą naśladować?
Jeśli commit odpowiada „tak” na przynajmniej jedno z tych pytań, jest kandydatem do ekstrakcji decyzji. Nasz typowy wskaźnik: 1-4 decyzje na 100 commitów (około 1-4%).
Dla wpisów changeloga próg jest niższy: każda zmiana widoczna dla użytkownika (funkcje, poprawki, usprawnienia) zostaje zapisana. Wewnętrzne porządki, aktualizacje dokumentacji i refaktoryzacje zazwyczaj są pomijane. Nasz typowy wskaźnik: 30-50 wpisów changeloga na 100 commitów.
Przechowywanie danych: ledgery tylko do dopisywania
System wydobywczy używa ledgerów JSONL tylko do dopisywania (append-only) dla bezkonfliktowej pracy wieloagentowej:
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
└── ...
Format JSONL z merge=union w .gitattributes oznacza, że wielu agentów może klasyfikować commity jednocześnie bez konfliktów scalania. Każda linia jest niezależna.
Bramki walidacyjne
Przed każdą sesją wydobywczą uruchamiamy walidację:
uv run orkestra mine validate --quick
Sprawdza to:
- Poprawność formatu SHA
- Zgodność formatu identyfikatora decyzji
- Brak zduplikowanych wpisów dla tego samego SHA
- Czy przywoływane decyzje faktycznie istnieją
Po klasyfikacji walidujemy ponownie przed zatwierdzeniem zmian.
Dlaczego to ma znaczenie
Pętla sprzężenia zwrotnego, którą zbudowaliśmy, rozwiązuje kilka problemów:
Dla nowych członków zespołu: Zamiast pytać „dlaczego zrobiliśmy X?”, mogą przeszukać rejestr decyzji. Kontekst jest zachowany.
Dla agentów AI: Nie działają w próżni. Mogą odpytywać wiedzę instytucjonalną, zanim wydadzą rekomendację. Poproszeni o dodanie nowego etapu pipeline’u, mogą odkryć wzorzec DuckDB i się go trzymać.
Dla spójności architektonicznej: Decyzje są jednoznaczne i przeszukiwalne. Gdy ktoś proponuje podejście sprzeczne z istniejącą decyzją, system może uwidocznić ten konflikt.
Dla generowania changeloga: Notatki wydania nie są gorączkowym pośpiechem w ostatniej chwili. Są produktem ubocznym ciągłej klasyfikacji podczas rozwoju.
Dla onboardingu: Nowi agenci dziedziczą pełny kontekst bazy kodu. Widzą nie tylko kod — widzą decyzje, które go ukształtowały.
Stan obecny
Na dziś:
- 15 637 commitów przetworzonych przez pipeline
- 476 decyzji architektonicznych wyodrębnionych i udokumentowanych
- 6799 wpisów changeloga zapisanych
- 100% pokrycia w obu domenach
Każdy commit od momentu, gdy zaczęliśmy, został sklasyfikowany. Pamięć instytucjonalna jest kompletna i przeszukiwalna.
Jak zacząć
Jeśli chcesz wdrożyć coś podobnego:
-
Zacznij od konwencjonalnych commitów. Pipeline wydobywczy działa najlepiej, gdy commity mają ustrukturyzowane prefiksy (
feat:,fix:,chore:). -
Zdefiniuj swoje domeny. Używamy domen takich jak
pipeline,agent-design,observability,data-modeling. Organizują one decyzje według obszaru. -
Zbuduj nawyk klasyfikacji. Wydobywanie działa, gdy zespoły regularnie klasyfikują commity. Przetwarzanie wsadowe ze wsparciem LLM pomaga skalować.
-
Uczyń decyzje przeszukiwalnymi. Wartość kumuluje się, gdy agenci mogą przeszukiwać decyzje przez CLI. Struktura Twojego wyjścia powinna być pod kątem konsumpcji maszynowej.
-
Zamknij pętlę. Decyzje powinny wpływać na przyszłą pracę. Uwzględnij odniesienia do decyzji w instrukcjach agentów i listach kontrolnych przeglądu kodu.
Celem nie jest idealna dokumentacja. Chodzi o to, by powód stojący za zmianami był dostępny zarówno dla ludzi, jak i AI, dziś i za sześć miesięcy. Gdy zmiany stają się pamięcią instytucjonalną, zespoły budują na ustalonych wzorcach zamiast wymyślać je na nowo.
Przepływ pracy wydobywczy jest częścią naszego silnika orkiestracji, konkretnie modułu silnika kontekstu w naszym pakiecie orkiestracji.
Powiązane treści
Więcej z dziennika budowy Maguyva
Dlaczego zaktualizowaliśmy wyszukiwanie kodu do voyage-4-large_
Przenieśliśmy nasze embeddingi kodu na voyage-4-large — obecnie na szczycie publicznego rankingu RTEB dla wyszukiwania kodu. Wersja uczciwa: kompromis, na jaki idziemy, co faktycznie indeksujemy i dlaczego płacimy za embeddingi premium.
Rekurencyjne samodoskonalenie językowe: szlifowanie inteligencji kodu w ~280 językach_
Obsługujemy inteligencję kodu dla ~280 języków. Żaden człowiek nie jest w stanie tego ręcznie zweryfikować. Zbudowaliśmy więc pętlę rekurencyjnego samodoskonalenia językowego — wyrywkowa kontrola, LLM jako sędzia, naprawa jednej rzeczy, ponowna walidacja — i uruchamiamy ją z flotą izolowanych agentów, dopóki ekstrakcja nie będzie naprawdę poprawna, a nie tylko zielona.
Wielomodalne wyszukiwanie z fuzją: dobór właściwego retrievera do każdego zapytania_
Zapytanie w stylu „gdzie zdefiniowano parseConfig” potrzebuje innego wyszukiwania niż „jak działa autoryzacja”. Maguyva klasyfikuje intencję, odpowiednio waży cztery tryby wyszukiwania i łączy wyniki za pomocą ważonej Reciprocal Rank Fusion.