Pular para o conteúdo
cd /blog

Minerando o Loop: Como Mudanças Se Tornam Memória Institucional

[Arquitetura][Workflows]

> Commits do Git se tornam entradas estruturadas de changelog e registros de decisões arquiteturais, que depois realimentam agentes de IA como memória institucional consultável.

Os números neste post refletem o sistema no momento da publicação (fevereiro de 2026). Consulte nossa página da equipe para números atualizados.

Toda equipe de engenharia enfrenta o mesmo desafio: mudanças acontecem o tempo todo, mas o porquê por trás dessas mudanças desaparece. Seis meses depois, alguém pergunta “por que adotamos o DuckDB para os stages do pipeline?” e a resposta vive apenas na cabeça de quem tomou essa decisão — se essa pessoa ainda estiver por perto.

Construímos um workflow de mineração que fecha esse loop. As mudanças fluem através de commits do git, são processadas pelo nosso pipeline de mineração, tornam-se entradas estruturadas de changelog e registros de decisões arquiteturais, e depois realimentam nossos agentes de IA através de consultas de CLI. O resultado: memória institucional que tanto humanos quanto IA podem acessar.

O Problema: Decisões Evaporam

Considere um cenário típico. Um desenvolvedor faz um commit:

feat(canonical): add DuckDB runtime for pipeline stages

Esse commit representa uma escolha arquitetural significativa. A equipe avaliou opções, considerou trade-offs e chegou ao DuckDB por razões específicas. Mas todo esse contexto vive em:

  • Uma thread do Slack (provavelmente apagada)
  • A memória de alguém (definitivamente enfraquecendo)
  • Um comentário no código (talvez, se você tiver sorte)

Três meses depois, um novo membro da equipe pergunta: “devo usar DuckDB ou SQLite para esse novo stage?” Sem memória institucional, essa pessoa ou reinventa a roda ou faz escolhas inconsistentes.

O Loop: dos Commits ao Contexto

Nosso workflow de mineração transforma o histórico do git em conhecimento consultável:

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)     │
      └───────────────┘

O insight central: tanto os changelogs quanto as decisões arquiteturais fluem do mesmo histórico do git, processado por um pipeline unificado. Isso garante que nada escape pelas frestas.

Como a Mineração Funciona

Etapa 1: Sincronizar o Índice

uv run orkestra mine sync

Esse comando varre o histórico do git e constrói um índice de todos os commits. Ele extrai sinais estruturados de cada commit:

  • Tipo de commit convencional (feat, fix, chore, docs)
  • Escopo (qual pacote ou área)
  • Marcadores de breaking change
  • Arquivos alterados e métricas de complexidade

Etapa 2: Verificar o Status de Cobertura

uv run orkestra mine status

É assim que o nosso status atual se parece:

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 commits processados. 476 se tornaram decisões arquiteturais. 6.799 se tornaram entradas de changelog. Todo commit classificado.

Etapa 3: Obter Candidatos para Revisão

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

Isso traz à tona commits que ainda não foram processados, com contexto completo para classificação:

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

Os sinais ajudam a guiar a classificação: is_releasable_type: true sugere que isso deveria aparecer no changelog. A grande contagem de inserções e os arquivos de infraestrutura sugerem que também pode ser uma decisão arquitetural.

Etapa 4: Classificar Commits

Dois caminhos se separam aqui: entradas de changelog e decisões arquiteturais.

Para entradas de changelog:

uv run orkestra mine classify abc123 --changelog added

Isso registra que o commit abc123 deve aparecer no changelog na categoria “Added”.

Para decisões arquiteturais:

Primeiro, obtenha um ID de decisão real:

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

Depois classifique com o ID da decisão:

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

Isso vincula o commit a um registro de decisão que será criado ou atualizado.

Para processamento em lote (o que fazemos na prática):

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

O formato JSONL suporta ambos os domínios em uma única passagem:

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"}

Etapa 5: Renderizar as Saídas

uv run orkestra changelog render --package <pkg>

Isso gera arquivos CHANGELOG.md por pacote a partir do ledger. Os changelogs são artefatos derivados — apague-os e eles se regeneram perfeitamente a partir do ledger de origem.

A Estrutura do Registro de Decisão

As decisões extraídas se tornam arquivos YAML com metadados ricos:

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

Toda decisão remete de volta aos seus commits de origem. Toda decisão especifica quais arquivos ela afeta. Os relacionamentos entre decisões são explícitos.

Integração com a CLI: Consultando a Memória Institucional

É aqui que o loop se fecha. Os agentes podem consultar decisões através da CLI:

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

Retorna decisões sobre lógica de retry, tratamento de erros, padrões de recuperação.

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

Retorna o registro de decisão completo com contexto, justificativa e impacto.

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

Mostra quais escolhas arquiteturais foram feitas recentemente.

Como os Agentes Usam Isso

As instruções de base do nosso orquestrador incluem:

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

Quando um agente recebe a tarefa de implementar algo relacionado ao DuckDB, ele pode primeiro checar:

uv run orkestra decisions search --query "DuckDB"

E descobrir a DEC-PL-142, aprendendo:

  • Por que escolhemos o DuckDB (context)
  • Como usá-lo corretamente (agent_guidance)
  • Quais arquivos examinar (files)
  • Quais decisões relacionadas existem (related)

O agente não reinventa a roda. Ele constrói sobre padrões já estabelecidos.

O Teste das Três Perguntas

Nem todo commit merece um registro de decisão. Usamos o Teste das Três Perguntas para filtrar:

  1. Isso foi difícil de decidir? Exigiu análise significativa, avaliação de trade-offs ou debate?
  2. É custoso de mudar? Reverter essa decisão exigiria retrabalho significativo?
  3. Tem impacto em todo o sistema? Afeta múltiplos pacotes ou estabelece padrões que outros vão seguir?

Se um commit responde “sim” a pelo menos uma dessas perguntas, ele é candidato à extração de decisão. Nossa taxa típica: 1 a 4 decisões a cada 100 commits (cerca de 1–4%).

Para entradas de changelog, a barra é mais baixa: qualquer mudança visível ao usuário (funcionalidades, correções, melhorias) é registrada. Tarefas internas, atualizações de documentação e refatorações costumam ser ignoradas. Nossa taxa típica: 30 a 50 entradas de changelog a cada 100 commits.

Armazenamento de Dados: Ledgers Somente-Anexação

O sistema de mineração usa ledgers JSONL somente-anexação para operação multiagente sem conflitos:

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
    └── ...

O formato JSONL com merge=union em .gitattributes significa que vários agentes podem classificar commits simultaneamente sem conflitos de merge. Cada linha é independente.

Gates de Validação

Antes de qualquer sessão de mineração, rodamos validação:

uv run orkestra mine validate --quick

Isso verifica:

  • Validade do formato do SHA
  • Conformidade do formato do ID de decisão
  • Ausência de entradas duplicadas para o mesmo SHA
  • Se as decisões referenciadas realmente existem

Após a classificação, validamos novamente antes de fazer commit das mudanças.

Por Que Isso Importa

O loop de feedback que construímos resolve vários problemas:

Para novos membros da equipe: em vez de perguntar “por que fizemos X?”, eles podem buscar no registro de decisões. O contexto é preservado.

Para agentes de IA: eles não operam no vácuo. Podem consultar conhecimento institucional antes de fazer recomendações. Quando solicitados a adicionar um novo stage de pipeline, podem descobrir o padrão do DuckDB e segui-lo.

Para consistência arquitetural: as decisões são explícitas e pesquisáveis. Quando alguém propõe uma abordagem que contradiz uma decisão existente, o sistema pode revelar o conflito.

Para a geração de changelog: as notas de release não são uma correria de última hora. São um subproduto da classificação contínua durante o desenvolvimento.

Para onboarding: novos agentes herdam o contexto completo do codebase. Eles não veem apenas o código — veem as decisões que o moldaram.

Estado Atual

Atualmente:

  • 15.637 commits processados pelo pipeline
  • 476 decisões arquiteturais extraídas e documentadas
  • 6.799 entradas de changelog registradas
  • 100% de cobertura em ambos os domínios

Todo commit desde que começamos foi classificado. A memória institucional está completa e é consultável.

Começando

Se você quer implementar algo parecido:

  1. Comece com commits convencionais. O pipeline de mineração funciona melhor quando os commits têm prefixos estruturados (feat:, fix:, chore:).

  2. Defina os seus domínios. Usamos domínios como pipeline, agent-design, observability, data-modeling. Eles organizam as decisões por área.

  3. Construa o hábito de classificação. A mineração funciona quando as equipes classificam commits regularmente. O processamento em lote com assistência de LLM ajuda a escalar.

  4. Torne as decisões consultáveis. O valor se acumula quando os agentes podem buscar decisões via CLI. Estruture a sua saída para consumo por máquina.

  5. Feche o loop. As decisões devem influenciar o trabalho futuro. Inclua referências a decisões nas instruções dos agentes e nas checklists de revisão de código.

O objetivo não é documentação perfeita. É tornar o porquê por trás das mudanças acessível tanto para humanos quanto para IA, hoje e daqui a seis meses. Quando as mudanças se tornam memória institucional, as equipes constroem sobre padrões estabelecidos em vez de reinventá-los.


O workflow de mineração é parte do nosso motor de orquestração, especificamente o módulo de motor de contexto no nosso pacote de orquestração.

Leituras relacionadas

Mais do log de build do Maguyva