medallion-architecture
Skill0 starsChanged 43 days agoMITView on GitHub
Use ao decidir, escolher, definir, avaliar ou planejar estrategia arquitetural para pipelines NOVOS -- escolher entre DELETE+APPEND vs replaceWhere vs MERGE, definir estrategia de reprocessamento e idempotencia, decidir versionamento de regras, avaliar Jobs vs Declarative Pipelines. NAO use para revisar ou validar implementacoes Bronze/Silver/Gold existentes.
In this repository13 other files it gives its agents.
- artifact-documentationSkill
- asset-placementSkill
- code-reviewSkill
- data-quality-guardrailsSkill
- docs-syncSkill
- eda-and-validationSkill
- git-workflowSkill
- naming-conventionsSkill
- notebook-structureSkill
- project-contextSkill
- skill-patternsSkill
- technical-writingSkill
- unity-catalog-namingSkill
The file
We split this skill into the rules it gives an agent
1 rule. About 0 are common, 0 are distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 302
Nunca: DELETE WHERE em Bronze. Versionamento via coluna _versao_ingestao.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Arquitetura Medalhão
Versão: 1.0.1 | Data: 2026-08-18 | Domínio: architecture | Autor: Pedro O. Silva
Quando Usar Esta Skill
Carregar ao tomar decisões arquiteturais para pipelines NOVOS de dados: escolher entre estratégias de gravação (DELETE+APPEND, replaceWhere, MERGE), definir abordagem de reprocessamento e idempotência, decidir versionamento de regras de negócio, ou avaliar entre Jobs procedurais e Declarative Pipelines. NÃO usar para revisar ou validar implementações existentes de Bronze/Silver/Gold — esta skill orienta decisões de arquitetura, não auditoria de código.
1. O problema que a arquitetura resolve
A arquitetura medalhão não é sobre "ter três camadas". É uma resposta a uma tensão estrutural do processamento de dados: o dado bruto é confiável quanto à origem mas inútil para consumo; o dado refinado é útil mas frágil quanto à auditabilidade. Um único estágio força a escolher entre os dois. O medalhão desacopla essa tensão em estágios, cada um com um contrato próprio.
O ganho central é a reprocessabilidade: como cada camada é derivável da anterior por transformações determinísticas, qualquer erro de lógica é corrigível reprocessando a jusante, sem perda de origem. Isso só é verdade se a fronteira entre camadas for respeitada com rigor — é aí que a maioria das implementações falha.
2. Princípios fundamentais (o "porquê" antes do "como")
- Progressão monotônica de qualidade e semântica. Cada camada só adiciona estrutura, nunca a remove arbitrariamente. Bronze → Silver → Gold é um fluxo de refinamento crescente.
- Imutabilidade da origem. Bronze é a fronteira de verdade. Tudo a jusante é reconstruível; Bronze, não. Se você não consegue recriar Silver e Gold só a partir de Bronze, a arquitetura está quebrada.
- Determinismo das transformações. Reprocessar o mesmo Bronze deve produzir
o mesmo Silver/Gold — dada a mesma versão de regras. Não-determinismo
(ex.:
current_timestamp()como chave, ordenação instável em dedupe) destrói a reprodutibilidade e é uma fonte silenciosa de divergência. - Separação de responsabilidades por camada. Cada camada resolve UMA classe de problema. Misturar limpeza técnica (Silver) com regra de negócio (Gold) na mesma etapa é o antipadrão mais comum e o mais caro de desfazer.
3. Anatomia das camadas
3.1 Bronze — camada de captura (raw)
Contrato: representar fielmente o que a fonte entregou, com rastreabilidade de ingestão.
| Faz | NÃO faz |
| Ingestão as-is do dado bruto | Casting de tipos de negócio |
| Adiciona metadados técnicos de ingestão | Deduplicação |
| Preserva duplicatas, nulos, inconsistências | Aplicação de regra de negócio |
| Valida forma (arquivo/coluna existe?) | Transformação de conteúdo |
| Append-only (histórico de tudo que chegou) | Filtro semântico de linhas |
Metadados técnicos típicos (não descaracterizam o "raw" porque não alteram conteúdo):
df_bronze = (
df_raw
.withColumn("_ingest_ts", current_timestamp())
.withColumn("_source_file", input_file_name())
.withColumn("_run_id", lit(run_id))
.withColumn("_ingest_date", current_date())
)Distinção crítica — validar ≠ transformar. Validação de schema/arquivo no Bronze verifica e rejeita/alerta, mas não muda o conteúdo. É por isso que guardrails de validação de forma pertencem ao Bronze sem violar o "raw". Transformação de conteúdo é o que marca a passagem para Silver.
Formato: Delta, append-only. O padrão maduro usa ingestão incremental (Auto Loader) com checkpoint, garantindo exactly-once na captura de arquivos novos.
3.1.1 Landing Zone e Preservação de Arquivos Originais
Algumas arquiteturas separam Landing Zone (arquivos originais preservados) de Bronze (dados ingeridos em Delta). Esse padrão adiciona uma camada de auditabilidade e resiliência:
Landing Zone:
- Arquivos originais preservados exatamente como baixados da fonte
- Organizados por período/fonte em Unity Catalog Volumes
- Metadados HTTP preservados (Last-Modified, tamanho, checksum)
- Versionamento de arquivos: se a fonte atualiza arquivo histórico, nova versão
é preservada (ex.:
arquivo_2020.zip.v1,arquivo_2020.zip.v2)
Vantagens:
- Reprocessamento offline: Bronze pode ser reconstruído mesmo se a fonte externa ficar indisponível
- Auditoria forense: arquivo original disponível para validação/comparação
- Detecção de correções: rastrear quando a fonte atualizou dados históricos
- Cache local: reduz dependência de rede/APIs externas em reprocessamentos
Trade-off: duplicação de storage (arquivo + Delta). Vale quando:
- Fonte externa não é confiável (APIs instáveis, SLAs fracos)
- Requisitos de compliance exigem preservar arquivo original
- Fonte faz correções retroativas (arquivos históricos mudam)
# Estrutura típica de Landing Zone em UC Volume
/Volumes/catalog/schema/landing/
├── fonte_a/
│ ├── 2020/
│ │ ├── arquivo_2020.zip
│ │ ├── arquivo_2020.zip.v2 # Versão atualizada pela fonte
│ │ └── _metadata.json # Last-Modified, URL, timestamp
│ └── 2021/
│ └── arquivo_2021.zip
└── fonte_b/
└── ...Fluxo com Landing Zone:
Fonte externa → Landing Zone (Volume) → Bronze (Delta) → Silver → GoldDetecção de atualizações: comparar Last-Modified HTTP da fonte com metadado
local. Se mais recente, re-baixar e versionar. Bronze detecta novas versões via
tabela de controle.
3.2 Silver — camada de conformação (limpeza técnica)
Contrato: produzir um dado limpo, tipado e conformado, fiel ao grão da origem, mas ainda sem regra de negócio.
Transformações que pertencem aqui:
- Casting para tipos corretos (string → date/decimal/int).
- Deduplicação (definir a chave natural e a política de desempate — ordenação determinística obrigatória).
- Tratamento de nulos (rejeição, default, ou quarentena).
- Padronização (normalização de encoding, trim, casing, unidades).
- Conformação de schema entre múltiplas fontes que descrevem a mesma entidade.
- Validações de integridade (unicidade de chave, faixas válidas, invariantes de soma).
w = Window.partitionBy("chave_natural").orderBy(col("_ingest_ts").desc())
df_silver = (
df_bronze
.withColumn("valor", col("valor").cast("decimal(18,2)"))
.withColumn("_rn", row_number().over(w))
.filter(col("_rn") == 1) # dedupe determinístico
.drop("_rn")
.filter(col("chave_natural").isNotNull())
)A linha que não se cruza: se uma transformação depende de conhecimento de negócio ("custo do sistema X vai para a área Y"), ela não é Silver. Silver é limpeza agnóstica de negócio. O teste prático: um engenheiro sem contexto de domínio conseguiria escrever a regra? Se sim, é Silver. Se precisa de alguém do negócio para definir, é Gold.
3.3 Gold — camada de consumo (semântica de negócio)
Contrato: entregar dado modelado para consumo — agregações, regras de negócio aplicadas, modelagem dimensional, métricas prontas.
- Agregação ao grão de consumo (não mais o grão da origem).
- Regras de negócio (alocações, rateios, classificações, derivações).
- Modelagem (fatos e dimensões, ou tabelas wide orientadas a consumo).
- Invariantes de negócio (ex.: conservação — a soma alocada deve igualar a soma de entrada).
- Rastreabilidade de regra (qual regra produziu cada registro).
Ponto que a maioria ignora — versionamento de regra. Gold é onde a regra vive, e regra muda no tempo. Rastrear qual versão da regra produziu cada registro (ex.: coluna de rule-code concatenado por registro) é o que permite auditar e reprocessar corretamente. E leva à armadilha abaixo.
4. A fronteira mais difícil: reprocessamento histórico × versão de regra
Reprocessar Gold a partir de Bronze é trivial se a regra for a mesma. O problema aparece quando você reprocessa um período antigo hoje, com o código de regra de hoje:
- Se o objetivo é corrigir um bug → reprocessar com a regra atual é o certo.
- Se o objetivo é reconstruir o que foi reportado à época → você precisa aplicar a versão da regra vigente naquele momento, não a atual.
Esses dois objetivos são incompatíveis num pipeline que trata regra como código mutável. Reproduzir fielmente o passado exige que a regra seja versionada como dado (tabela de regras com vigência temporal) e não apenas como código:
-- regra como dado versionado, não como lógica hardcoded
SELECT f.*, r.rule_code
FROM fato f
JOIN dim_regra r
ON f.chave = r.chave
AND f.data_competencia BETWEEN r.vigencia_ini AND r.vigencia_fimSem isso, "reprocessar o histórico" e "preservar a versão de regra da época" são mutuamente exclusivos. Decidir qual dos dois você quer garantir é uma decisão de arquitetura, não de implementação — e precisa ser explícita.
5. Preocupações transversais
5.1 Idempotência (Propriedade Arquitetural, NÃO Guardrail)
IMPORTANTE: Idempotência não é um guardrail — é uma propriedade arquitetural que decorre da escolha da estratégia de gravação. Guardrails validam dados; idempotência define como o pipeline se comporta ao rodar múltiplas vezes.
Toda escrita a jusante deve ser idempotente: rodar duas vezes o mesmo período não pode duplicar nem divergir.
Como implementar idempotência por camada:
| Camada | Estratégia | Idempotente? | Como |
| Bronze | APPEND puro + versionamento | ❌ NÃO (por design) | Preserva histórico completo; filtro em Silver |
| Bronze | APPEND + verificação prévia | ✅ SIM | Checar se já processou antes de rodar |
| Silver/Gold | DELETE WHERE + APPEND | ✅ SIM | Remove período, depois insere |
| Silver/Gold | MERGE (upsert) | ✅ SIM | Atualiza existente, insere novo |
| Silver/Gold | replaceWhere | ✅ SIM | Substitui partição atomicamente |
| Silver/Gold | APPEND puro | ❌ NÃO | Duplica em reprocessamento (ANTIPADRÃO) |
Exemplo - Tornar Bronze idempotente via verificação prévia:
# Verificar se já foi processado
ja_processado = spark.sql(f"""
SELECT COUNT(*) as count
FROM proj_cvm_05_apoio.controle_ingestao
WHERE fonte = 'dre'
AND ano = {ano}
AND last_modified_cvm = '{last_modified_cvm}'
AND status = 'SUCCESS'
""").collect()[0]['count']
if ja_processado > 0:
print(f"⏭️ Ano {ano} já processado - pulando")
continue
# Processar e gravar
df_bronze.write.mode("append").saveAsTable("bronze.tabela")Trade-off Bronze: APPEND puro preserva todo histórico mas não é idempotente. Útil quando você quer rastrear quando cada versão chegou. Para idempotência, adicione verificação de estado ou use MERGE.
Padrões: MERGE por chave+competência, ou overwrite particionado (replaceWhere).
Append cego em camadas refinadas é antipadrão.
5.2 Governança (Unity Catalog)
As camadas mapeiam naturalmente para a hierarquia catálogo → schema → tabela.
Padrão comum: um schema (ou catálogo) por camada (bronze, silver, gold),
com permissões progressivamente mais amplas — Bronze restrito a engenharia, Gold
liberado para consumo analítico. Linhagem e controle de acesso vivem aqui, não no
código.
5.3 Qualidade
Guardrails posicionados por camada, cada um coerente com o contrato:
- Bronze: validação de forma (arquivo/coluna).
- Silver: dedupe, nulos, invariantes técnicas (ex.: variância de soma).
- Gold: regras de negócio, invariante de conservação, variância histórica.
Uma tabela de auditoria central + log de execução transforma os guardrails de "checagens dispersas" em observabilidade rastreável.
5.4 Observabilidade
Log de execução por camada + audit table + métricas de volume/rejeição. Sem isso, uma divergência em Gold é impossível de localizar entre 30 tabelas.
5.5 Estratégias de Gravação por Cenário
A escolha entre DELETE WHERE + APPEND, MERGE, e replaceWhere depende do padrão
de atualização dos dados e da camada:
Bronze: Sempre APPEND
# Bronze é append-only por definição
df_bronze.write.mode("append").saveAsTable("bronze.tabela")Nunca: DELETE WHERE em Bronze. Versionamento via coluna _versao_ingestao.
Silver/Gold: Cenários
Cenário 1: Ingestão batch periódica (ex: dados anuais/trimestrais)
# Estratégia: DELETE WHERE + APPEND
# Remove período sendo reprocessado, depois insere nova versão
# 1. Deletar período a ser reprocessado
spark.sql(f"""
DELETE FROM silver.tabela
WHERE ano IN ({','.join(map(str, anos_processar))})
""")
# 2. Inserir nova versão
df_silver.write.mode("append").saveAsTable("silver.tabela")Quando usar:
- Dados organizados em períodos fixos (ano, trimestre, mês)
- Reprocessamento por período completo (não por registro individual)
- Simplicidade: 2 comandos SQL sequenciais, fácil de debugar
- Não há risco de DELETE + APPEND parcial (ambos em mesma transação)
Vantagens:
- Idempotente: rodar N vezes produz mesmo resultado
- Simples de auditar (log explícito de DELETE + volume de INSERT)
- Performance previsível para volumes grandes
Desvantagens:
- Não funciona para streaming (precisa de período fechado)
- Window de DELETE + APPEND pode causar leituras inconsistentes se não transacionado
Cenário 2: Streaming ou CDC incremental
# Estratégia: MERGE (upsert)
from delta.tables import DeltaTable
delta_table = DeltaTable.forName(spark, "silver.tabela")
delta_table.alias("target").merge(
df_novos_dados.alias("source"),
"target.chave_natural = source.chave_natural"
).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute()Quando usar:
- Streaming contínuo ou micro-batches
- CDC (Change Data Capture): inserts, updates, deletes por registro
- Não há "período fechado" — dados chegam continuamente
Cenário 3: Sobrescrever partições específicas
# Estratégia: replaceWhere (Delta Lake)
df_silver.write \\
.mode("overwrite") \\
.option("replaceWhere", f"ano IN ({','.join(map(str, anos_processar))})") \\
.saveAsTable("silver.tabela")Quando usar:
- Tabela particionada por coluna de período
- Quer atomicidade: partição substituída em transação única
- Equivalente a DELETE WHERE + APPEND, mas atômico
Vantagens:
- Atômico: leitores não veem estado intermediário
- Otimizado para partições grandes
Desvantagens:
- Requer particionamento físico por coluna usada no
replaceWhere - Menos flexível que DELETE WHERE (precisa match exato com partição)
Resumo - Escolha por Contexto:
| Cenário | Bronze | Silver/Gold |
| Batch periódico (ano/trimestre) | APPEND | DELETE WHERE + APPEND ou replaceWhere |
| Streaming contínuo | APPEND | MERGE |
| CDC incremental | APPEND | MERGE |
| Versionamento histórico | APPEND | Filtro em query (via _versao_ingestao) |
Antipadrão: APPEND sem dedupe em Silver/Gold. Gera duplicatas em reprocessamento.
6. Antipadrões (o que quebra a arquitetura)
| Antipadrão | Consequência |
| Regra de negócio no Silver | Perde reprodutibilidade; Silver vira Gold |
| Bronze com transformação de conteúdo | Perde a fonte de verdade; sem rollback |
| Pular Silver (Bronze → Gold direto) | Limpeza e regra acopladas; indebugável |
| Regra como código mutável sem versão | Reprocessamento histórico infiel |
| Append não-idempotente em Silver/Gold | Duplicação em reprocessamento |
| Dedupe com ordenação não-determinística | Resultado varia entre execuções |
| Camadas sem contrato explícito | Fronteiras erodem; tudo vira "meio-Gold" |
7. Trade-offs e variações
- Raw/Landing antes do Bronze. Algumas arquiteturas separam "arquivos originais intocados" (landing) de "Delta ingerido com metadados" (Bronze). Muda o vocabulário, não o princípio.
- Camadas extras. Projetos grandes às vezes inserem uma camada intermediária (ex.: "Silver conformado" × "Silver enriquecido") ou uma camada de serving separada do Gold. Legítimo quando o grão de consumo diverge muito do grão limpo.
- Quando NÃO usar medalhão. Dado que já chega limpo e governado, pipelines triviais, ou latência ultra-baixa onde três hops são caros demais. Medalhão cobra em I/O e storage o que paga em auditabilidade — nem sempre vale.
8. Mapeamento para Databricks
| Conceito medalhão | Implementação Databricks |
| Tabelas de cada camada | Delta tables (Unity Catalog managed) |
| Ingestão incremental Bronze | Auto Loader (cloudFiles) + checkpoint |
| Transformação Silver/Gold | PySpark ou SQL |
| Qualidade declarativa | Expectations (Lakeflow Declarative Pipelines) |
| Orquestração procedural | Lakeflow Jobs (tasks de notebook encadeadas) |
| Orquestração declarativa | Lakeflow Declarative Pipelines (DAG automático) |
| Governança/linhagem | Unity Catalog |
Job vs Pipeline no contexto medalhão: um pipeline procedural (notebooks orquestrados por um Job) dá controle total e guardrails customizados por camada, ao custo de você manter a ordem e as validações na mão. Uma Declarative Pipeline infere o DAG entre camadas e move os guardrails para expectations declarativas, ao custo de menos controle fino. A escolha depende de quanto da sua lógica de qualidade é expressável declarativamente — migrar guardrails imperativos ricos para expectations nem sempre é 1:1.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

