Silver Técnica e Silver Analítica: o coração confiável do lakehouse
6 de out. de 2026 · @Michel Santana

Introdução: a Silver que tenta ser tudo
A arquitetura medalhão virou o padrão de fato dos lakehouses. Bronze, Silver e Gold são fáceis de desenhar em um slide. O problema aparece quando o projeto cresce: a Silver, que deveria ser a camada confiável, passa a acumular responsabilidades que puxam em direções opostas.
De um lado, ela precisa ser fiel à origem: tipar, deduplicar, aplicar CDC, guardar histórico e permitir conciliação com o sistema transacional. Do outro, precisa ser útil para o negócio: integrar fontes, aplicar regras, dar nomes que a área entende e servir de base para a Gold. Quando as duas coisas vivem na mesma tabela, acontecem três sintomas clássicos:
Uma regra de negócio muda e é preciso reprocessar desde a Bronze, porque a regra está misturada com a deduplicação.
Um incidente de ingestão contamina KPIs sem que ninguém perceba, porque não há fronteira de validação entre "dado correto" e "dado interpretado".
Ninguém sabe dizer se um campo veio do sistema de origem ou foi derivado por alguém em algum notebook.
Este artigo defende a divisão da Silver em duas camadas com contratos distintos:
Silver Técnica: o estado confiável e rastreável de cada registro da origem. Responde "o que o sistema diz?".
Silver Analítica: as entidades de negócio curadas por domínio. Responde "o que isso significa?".
Vou usar como referência a arquitetura end-to-end que adoto nos meus projetos. Ela tem 12 etapas, mas aqui o foco são as etapas 7 a 10: validação técnica, Silver Técnica, Silver Analítica e validação analítica. As demais aparecem apenas quando ajudam a entender o que entra e o que sai das duas Silvers.
A arquitetura de referência

A Figura 1 mostra o fluxo completo em 12 etapas, sustentado por seis pilares transversais: governança, qualidade e testes, observabilidade, contratos de dados, operação e controle, e princípios do fluxo. Em resumo:
Etapa | Papel no fluxo | Relação com as Silvers |
1. Fontes de dados | APIs, arquivos, bancos e fontes externas | Origem do que a Silver Técnica espelha |
2. Orquestração e ingestão | Captura, disparo e monitoramento das cargas | Define janelas e lotes que a Silver processa |
3. Landing Zone | Arquivos brutos imutáveis | Base para reprocessamento por arquivo |
4. Catálogo e governança | Catálogo, permissões, linhagem, metadados | Registra as duas Silvers e sua linhagem |
5. Descoberta e preflight | Encoding, delimitador, schema, hash, duplicidade | Barra arquivos ruins antes de chegarem à Bronze |
6. Bronze (append-only) | Ingestão bruta com histórico e metadados | Única fonte de leitura da Silver Técnica |
7. Validação técnica | Colunas obrigatórias, chaves, parsing, tipos | Portão de entrada da Silver Técnica |
8. Silver Técnica | Padronização, dedup, CDC, SCD, estado atual e histórico | Foco deste artigo |
9. Silver Analítica | Views, materialized views, modelos por domínio | Foco deste artigo |
10. Validação analítica | Regras de negócio, métricas, consistências | Portão de saída da Silver Analítica |
11. Gold | Star schema, fatos, dimensões conformadas, marts | Único consumidor obrigatório da Silver Analítica |
12. Consumo | BI, relatórios, APIs, consumidores analíticos | Consome a Gold, raramente a Silver |
Dois detalhes da arquitetura são decisivos para o restante do artigo:
Existem três quarentenas, não uma: de arquivos (após o preflight), técnica (após a etapa 7) e analítica (após a etapa 10). Cada Silver tem a sua própria fronteira de rejeição.
O reprocessamento é uma capacidade de primeira classe: backfill, repair run, reprocessamento por arquivo, por período e full refresh controlado. A separação das Silvers determina de onde cada reprocessamento parte.
O que chega antes: o contrato de entrada da Silver
A qualidade da Silver Técnica depende do que as etapas anteriores já garantiram. Vale entender o que ela pode assumir como verdade e o que ainda precisa verificar.
Preflight e Quarentena de Arquivos (etapa 5)
O preflight atua no nível do arquivo, não do registro. Ele detecta encoding, delimitador, cabeçalho e schema, calcula o hash do arquivo e verifica duplicidade. Arquivos com schema incompatível, vazios, com delimitador inconclusivo, conteúdo duplicado ou snapshot conflitante vão para a Quarentena de Arquivos e nunca chegam à Bronze.
O resultado é registrado em tabelas de controle como file_manifest, file_preflight_result e snapshot_comparison. Para a Silver, isso significa uma garantia importante: todo lote na Bronze tem origem conhecida e estrutura reconhecível.
Bronze append-only (etapa 6)
A Bronze guarda tudo o que chegou, na ordem em que chegou, com padronização mínima e metadados de ingestão: arquivo de origem, lote, timestamp de chegada e controle de origem. Ela nunca sofre UPDATE nem DELETE de negócio.
O que a Silver Técnica pode assumir da Bronze:
O arquivo de origem foi validado estruturalmente.
Cada registro carrega rastreabilidade até o arquivo e o lote.
Nada foi descartado sem registro.
O que a Silver Técnica não pode assumir:
Que não existem duplicatas de registro (o mesmo id pode chegar várias vezes).
Que os valores estão no tipo correto (a Bronze guarda frequentemente como STRING).
Que os eventos chegaram em ordem.
Que a chave de cada registro está presente e é válida.
É exatamente essa lacuna que a etapa 7 fecha.
Validação técnica e Quarentena Técnica (etapa 7)
A validação técnica é o portão de entrada da Silver Técnica. Ela trabalha no nível do registro e responde a uma única pergunta: este registro é estruturalmente utilizável? Não importa ainda se ele faz sentido para o negócio.
O que é validado
Verificação | Exemplo de regra | Motivo de rejeição |
Colunas obrigatórias | id_contrato, data_atualizacao presentes | chave ausente |
Chaves | chave natural não nula e com formato válido | chave ausente |
Parsing | JSON/linha desserializável | parse inválido |
Tipos e formatos | valor conversível para DECIMAL(18,2), data em formato ISO | valor incompatível |
Integridade estrutural | número de colunas e posições coerentes | linha corrompida |
Como implementar
O padrão é usar try_cast e funções tolerantes (try_to_timestamp, try_parse_json) para nunca quebrar o pipeline por um registro ruim. Cada registro recebe uma lista de motivos de rejeição; quem tem lista vazia segue para a Silver Técnica, quem não tem vai para a quarentena.
CREATE OR REPLACE TEMPORARY VIEW contrato_validado AS
SELECT
b.*,
try_cast(b.id_contrato AS BIGINT) AS id_contrato_tipado,
try_cast(b.valor_contratado AS DECIMAL(18,2)) AS valor_contratado_tipado,
try_to_timestamp(b.data_atualizacao, 'yyyy-MM-dd HH:mm:ss') AS data_atualizacao_tipada,
filter(array(
CASE WHEN b.id_contrato IS NULL THEN 'chave_ausente' END,
CASE WHEN b.id_contrato IS NOT NULL
AND try_cast(b.id_contrato AS BIGINT) IS NULL THEN 'chave_formato_invalido' END,
CASE WHEN b.valor_contratado IS NOT NULL
AND try_cast(b.valor_contratado AS DECIMAL(18,2)) IS NULL THEN 'valor_incompativel' END,
CASE WHEN try_to_timestamp(b.data_atualizacao,
'yyyy-MM-dd HH:mm:ss') IS NULL THEN 'data_atualizacao_invalida' END
), m -> m IS NOT NULL) AS motivos_rejeicao
FROM fenix_prd.bronze_core_bancario.contrato b
WHERE b._id_lote > :ultimo_lote_processado;No Lakeflow, as mesmas regras viram expectations. A diferença é que expect_or_drop descarta e só conta; para manter o registro rejeitado, o padrão recomendado é inverter a regra em um fluxo separado que grava a quarentena:
regras = {
"chave_presente": "id_contrato IS NOT NULL",
"chave_numerica": "try_cast(id_contrato AS BIGINT) IS NOT NULL",
"data_valida": "try_to_timestamp(data_atualizacao) IS NOT NULL",
}
condicao_valida = " AND ".join(f"({r})" for r in regras.values())
@dp.table(name="quarentena_core_bancario.contrato_tecnica")
def quarentena_tecnica():
return (spark.readStream.table("fenix_prd.bronze_core_bancario.contrato")
.where(f"NOT ({condicao_valida})")
.withColumn("_etapa", F.lit("validacao_tecnica"))
.withColumn("_quarentenado_em", F.current_timestamp()))
@dp.view
@dp.expect_all_or_drop(regras)
def contrato_valido():
return spark.readStream.table("fenix_prd.bronze_core_bancario.contrato")Como deve ser a Quarentena Técnica
Preserva o registro original intacto, com todas as colunas da Bronze e os metadados de lote.
Registra o motivo em formato estruturado (array de códigos), não em texto livre.
Registra etapa, regra e versão do contrato que causou a rejeição.
Tem estado: pendente, corrigido na origem, reprocessado, descartado com justificativa.
Gera métrica: taxa de rejeição por lote e por regra, com alerta acima de um limite definido no contrato.
A Quarentena Técnica é responsabilidade da engenharia. Um aumento repentino de rejeições quase sempre indica mudança no sistema de origem, não erro de negócio.
Silver Técnica em profundidade (etapa 8)
A Silver Técnica transforma o histórico de chegadas da Bronze em um estado consolidado por chave, ainda organizado por sistema de origem. Seu contrato é com o sistema transacional: o dono da origem deve reconhecer o próprio dado, apenas limpo, consolidado e rastreável.
Propósito
Ser a única versão confiável de cada entidade de cada fonte.
Ser reprocessável de forma determinística a partir da Bronze.
Ser conciliável com a origem: contagens, somas e chaves batem.
Isolar toda a complexidade técnica (CDC, ordenação, deletes, histórico) para que a Silver Analítica não precise lidar com ela.
Os nove blocos de responsabilidade
1. Staging. Uma view ou tabela intermediária com o lote atual já validado e tipado. Ela desacopla a leitura da Bronze da escrita na Silver e facilita reprocessar só um lote.
2. Padronizações. Somente técnicas: snake_case, trim, encoding, datas em UTC, nulos semânticos ('', 'NULL', '0000-00-00') convertidos para NULL, booleanos uniformes. O valor de negócio não muda: o código de situação 'A' continua 'A'.
3. Controles. Colunas técnicas com prefixo _ em todas as tabelas: _sistema_origem, _id_lote, _arquivo_origem, _id_execucao, _ingerido_em, _atualizado_em, _versao_contrato. Elas fazem a ponte com file_manifest e ingestion_registry.
4. Deduplicação. Last record wins por chave natural, ordenando pelo critério mais confiável disponível, nesta ordem de preferência: sequência do CDC (LSN, binlog position), timestamp de alteração da origem, ordem do arquivo no lote.
5. Hashes técnicos. Um hash SHA-256 das colunas de negócio (_hash_registro) permite detectar se o registro realmente mudou. Sem ele, cada recarga gera updates vazios, infla o histórico SCD2 e polui o Change Data Feed.
6. Chaves substitutas. Uma chave técnica estável (sk_contrato) que isola a plataforma de mudanças de formato da chave da origem e unifica chaves compostas. Prefira chaves determinísticas (hash de sistema de origem + chave natural) em vez de IDENTITY: em um full refresh, a chave determinística é recalculada igual; a IDENTITY gera novos valores e quebra quem já referenciava a antiga.
7. CDC e snapshots. Se a origem entrega CDC, aplica-se insert, update e delete com controle de ordem. Se entrega apenas snapshots completos, a Silver Técnica compara o snapshot atual com o anterior para derivar inclusões, alterações e exclusões (o mesmo papel de snapshot_comparison na etapa 5, agora no nível do registro).
8. SCD Tipo 1 e Tipo 2. Tipo 1 para o estado atual. Tipo 2 quando a origem não guarda histórico e o negócio, a auditoria ou a regulação precisam saber o valor em uma data passada.
9. Estado atual e histórico. O padrão que adoto é publicar duas tabelas por entidade: contrato (uma linha por chave, estado atual) e contrato_historico (SCD2 com _valido_de, _valido_ate, _registro_atual). A maioria dos consumidores só precisa da primeira; a segunda existe para auditoria e para a Gold reconstruir dimensões históricas.
O que a Silver Técnica NÃO faz
Não traduz códigos para descrições de negócio.
Não faz joins entre sistemas diferentes.
Não aplica regras de classificação, faixas ou flags de negócio.
Não muda o grão da origem nem agrega.
Implementação com MERGE incremental
Quando o pipeline é orquestrado por jobs e tabela de controle, o padrão é staging deduplicado e MERGE condicionado ao hash:
-- 1. Staging: lote validado, tipado e deduplicado
CREATE OR REPLACE TEMPORARY VIEW stg_contrato AS
SELECT * EXCEPT (rn) FROM (
SELECT
sha2(concat_ws('||', 'core_bancario', id_contrato_tipado), 256) AS sk_contrato,
id_contrato_tipado AS id_contrato,
valor_contratado_tipado AS valor_contratado,
nullif(trim(situacao), '') AS situacao,
to_utc_timestamp(data_atualizacao_tipada, 'America/Sao_Paulo') AS data_atualizacao,
operacao,
sha2(concat_ws('||', valor_contratado_tipado, trim(situacao)), 256) AS _hash_registro,
'core_bancario' AS _sistema_origem,
_id_lote, _arquivo_origem, _ingerido_em,
row_number() OVER (
PARTITION BY id_contrato_tipado
ORDER BY sequencia_cdc DESC, _ingerido_em DESC
) AS rn
FROM contrato_validado
WHERE size(motivos_rejeicao) = 0
) WHERE rn = 1;
-- 2. Estado atual (SCD1) com detecção real de mudança
MERGE INTO fenix_prd.silver_tec_core_bancario.contrato AS t
USING stg_contrato AS s
ON t.id_contrato = s.id_contrato
WHEN MATCHED AND s.operacao = 'D' THEN DELETE
WHEN MATCHED AND s.data_atualizacao >= t.data_atualizacao
AND s._hash_registro <> t._hash_registro THEN UPDATE SET
t.valor_contratado = s.valor_contratado,
t.situacao = s.situacao,
t.data_atualizacao = s.data_atualizacao,
t._hash_registro = s._hash_registro,
t._id_lote = s._id_lote,
t._arquivo_origem = s._arquivo_origem,
t._atualizado_em = current_timestamp()
WHEN NOT MATCHED AND s.operacao <> 'D' THEN INSERT (
sk_contrato, id_contrato, valor_contratado, situacao, data_atualizacao,
_hash_registro, _sistema_origem, _id_lote, _arquivo_origem, _ingerido_em, _atualizado_em
) VALUES (
s.sk_contrato, s.id_contrato, s.valor_contratado, s.situacao, s.data_atualizacao,
s._hash_registro, s._sistema_origem, s._id_lote, s._arquivo_origem, s._ingerido_em, current_timestamp()
);Repare em três detalhes: a condição s.data_atualizacao >= t.data_atualizacao protege contra eventos atrasados sobrescrevendo dados mais novos; a comparação de hash evita updates vazios; e a chave substituta é calculada, não gerada, por isso sobrevive a um full refresh.
Implementação declarativa com Lakeflow
Com Lakeflow Declarative Pipelines, estado atual e histórico saem de dois fluxos AUTO CDC sobre a mesma view validada:
from pyspark import pipelines as dp
from pyspark.sql import functions as F
# Estado atual: SCD Tipo 1
dp.create_streaming_table("silver_tec_core_bancario.contrato")
dp.create_auto_cdc_flow(
target="silver_tec_core_bancario.contrato",
source="contrato_valido",
keys=["id_contrato"],
sequence_by=F.col("sequencia_cdc"),
apply_as_deletes=F.expr("operacao = 'D'"),
except_column_list=["operacao", "sequencia_cdc"],
stored_as_scd_type=1,
)
# Histórico: SCD Tipo 2, versionando só o que importa
dp.create_streaming_table("silver_tec_core_bancario.contrato_historico")
dp.create_auto_cdc_flow(
target="silver_tec_core_bancario.contrato_historico",
source="contrato_valido",
keys=["id_contrato"],
sequence_by=F.col("sequencia_cdc"),
apply_as_deletes=F.expr("operacao = 'D'"),
except_column_list=["operacao", "sequencia_cdc"],
stored_as_scd_type=2,
track_history_column_list=["valor_contratado", "situacao"],
)O track_history_column_list faz o papel do hash técnico no SCD2: só mudanças nessas colunas abrem uma nova versão. Para fontes que só entregam snapshots, o equivalente é create_auto_cdc_from_snapshot_flow, que compara snapshots sucessivos e deriva as mudanças.
Silver Analítica em profundidade (etapa 9)
A Silver Analítica muda o eixo de organização: deixa de ser por sistema e passa a ser por domínio de negócio. Aqui, as várias Silvers Técnicas convergem para entidades conformadas (cliente, contrato, transação, produto) com regras de negócio explícitas, versionadas e testadas. Seu contrato é com o negócio.
Propósito
Ser a única definição de cada entidade de negócio, reutilizada por todos os modelos Gold.
Concentrar as regras de negócio em um lugar revisável, em vez de espalhá-las pelos marts.
Oferecer dados com semântica clara para quem não deveria precisar conhecer os sistemas de origem: analistas, cientistas de dados, Genie spaces e agentes de IA.
Os quatro blocos de responsabilidade
1. Curadoria por domínio. Cada domínio (cadastro, crédito, pagamentos, relacionamento) tem seu schema e seu dono. A curadoria inclui:
Integração entre fontes com regras explícitas de precedência (survivorship): o e-mail do CRM vence o do core; o endereço mais recente vence.
Conformação de chaves: uma chave de negócio estável (CPF/CNPJ normalizado, número do contrato) e tabelas de-para quando sistemas usam identificadores diferentes.
Tradução semântica: códigos viram descrições ('A' vira 'Ativo'), colunas ganham nomes completos, sem siglas do legado.
Derivações de negócio: tipo de pessoa, faixa de risco, cliente ativo, data da primeira contratação.
2. Views. Para transformações leves e sempre atuais: renomear, traduzir códigos, filtrar registros lógicos excluídos. Custo zero de armazenamento, mas o custo de cálculo é pago a cada consulta.
3. Materialized views. Para integrações e derivações mais pesadas que precisam de atualização incremental gerenciada. No Databricks, a materialized view é atualizada pelo próprio motor, que tenta recalcular só o que mudou a partir do Change Data Feed das Silvers Técnicas.
4. Modelos analíticos. Tabelas incrementais (normalmente via dbt) quando você precisa de controle explícito da lógica incremental, testes acoplados e revisão por pull request.
Qual forma de materialização usar
Situação | Forma recomendada | Por quê |
Renomear e traduzir uma única fonte | View | Sem custo de armazenamento, sempre atual |
Integração de 2 ou mais fontes, volume moderado | Materialized view | Refresh incremental gerenciado, pouco código |
Volume alto, lógica incremental específica | Modelo incremental (dbt merge) | Controle total do filtro incremental e do MERGE |
Regra complexa com muitos testes e revisão de negócio | Modelo dbt | Versionamento, documentação e testes no mesmo lugar |
Necessidade de histórico de negócio | Modelo dbt snapshot ou SCD2 lido da Silver Técnica | O histórico técnico já existe; aqui só se reinterpreta |
O que a Silver Analítica NÃO faz
Não lê da Bronze nem reaplica deduplicação: lê apenas da Silver Técnica.
Não é star schema: não tem fatos e dimensões desenhados para um BI específico. Isso é Gold.
Não agrega para um caso de uso (KPI mensal, ranking). Também é Gold.
Não esconde regra de negócio sem documentação: toda derivação tem descrição e teste.
Exemplo: materialized view de domínio
CREATE OR REPLACE MATERIALIZED VIEW fenix_prd.silver_cadastro.cliente
COMMENT 'Cliente conformado entre core bancário e CRM. Grão: um registro por CPF/CNPJ.'
AS
WITH core AS (
SELECT
regexp_replace(cpf_cnpj, '[^0-9]', '') AS documento,
nome, email, situacao, data_cadastro, data_atualizacao
FROM fenix_prd.silver_tec_core_bancario.cliente
),
crm AS (
SELECT
regexp_replace(documento, '[^0-9]', '') AS documento,
email, telefone, data_atualizacao
FROM fenix_prd.silver_tec_crm.contato
)
SELECT
core.documento AS chave_cliente,
CASE length(core.documento) WHEN 11 THEN 'PF'
WHEN 14 THEN 'PJ' END AS tipo_pessoa,
initcap(core.nome) AS nome_cliente,
coalesce(crm.email, core.email) AS email_principal,
crm.telefone AS telefone_principal,
CASE core.situacao WHEN 'A' THEN 'Ativo'
WHEN 'B' THEN 'Bloqueado'
WHEN 'I' THEN 'Inativo' END AS situacao_cadastral,
core.data_cadastro AS data_cadastro,
greatest(core.data_atualizacao, crm.data_atualizacao) AS data_ultima_atualizacao,
'v2' AS versao_regra
FROM core
LEFT JOIN crm ON crm.documento = core.documento;Note a coluna versao_regra: quando a regra de precedência ou de tradução mudar, a versão muda junto, e qualquer consumidor consegue saber sob qual regra o dado foi produzido.
Exemplo: modelo incremental em dbt
-- models/silver/credito/contrato.sql
{{ config(
materialized = 'incremental',
incremental_strategy = 'merge',
unique_key = 'numero_contrato',
liquid_clustered_by = ['data_contratacao'],
schema = 'silver_credito'
) }}
select
c.id_contrato as numero_contrato,
cli.chave_cliente,
c.valor_contratado,
c.data_contratacao,
c.data_vencimento_final,
{{ traduzir_situacao_contrato('c.situacao') }} as situacao_contrato,
case when c.dias_atraso > 90 then true else false end as indicador_inadimplente,
c.data_atualizacao as data_atualizacao_origem
from {{ source('silver_tec_core_bancario', 'contrato') }} c
join {{ ref('cliente') }} cli
on cli.chave_cliente = regexp_replace(c.cpf_cnpj, '[^0-9]', '')
{% if is_incremental() %}
where c.data_atualizacao > (select max(data_atualizacao_origem) from {{ this }})
{% endif %}A regra de tradução de situação fica em uma macro (traduzir_situacao_contrato), reutilizável e testável. A regra de inadimplência fica explícita no modelo, com nome de coluna que se explica sozinho.
Validação analítica e Quarentena Analítica (etapa 10)
Se a validação técnica pergunta "este registro é utilizável?", a validação analítica pergunta "este dado faz sentido para o negócio?". Ela é o portão de saída da Silver Analítica: nada chega à Gold sem passar por aqui.
As cinco famílias de validação
Família | O que verifica | Exemplo |
Regras de negócio | Condições que o negócio declara como verdadeiras | Contrato liquidado não pode ter saldo devedor |
Métricas | Totais e distribuições dentro do esperado | Soma do valor contratado bate com a Silver Técnica (tolerância 0,01%) |
Consistência analítica | Integridade referencial e coerência entre entidades | Todo contrato tem cliente existente em silver_cadastro.cliente |
Consistência temporal | Ordem lógica de datas e continuidade de séries | data_vencimento_final >= data_contratacao; nenhum dia sem transações em dia útil |
Restrições | Domínios e limites de valores | situacao_contrato dentro da lista aceita; taxa entre 0% e 30% a.m. |
Bloquear, isolar ou alertar
Nem toda falha analítica deve ter o mesmo tratamento. Defino três níveis no contrato de cada tabela:
Bloqueante: a carga inteira para. Usado para falhas que invalidam o conjunto (reconciliação de totais fora da tolerância, chave de negócio duplicada).
Isolante: o registro vai para a Quarentena Analítica e o restante segue. Usado para falhas pontuais (um contrato sem cliente, uma data incoerente).
Alerta: o registro segue, mas a violação é registrada e notificada. Usado para anomalias estatísticas (volume 40% abaixo da média de 4 semanas).
Implementação com testes dbt
models:
- name: contrato
description: Contrato de crédito conformado. Grão: um registro por número de contrato.
config:
meta:
dono: dominio_credito
versao_contrato: 2.1.0
data_tests:
- dbt_utils.expression_is_true:
name: vencimento_apos_contratacao
expression: "data_vencimento_final >= data_contratacao"
config: { severity: warn, store_failures: true }
columns:
- name: numero_contrato
data_tests: [not_null, unique] # bloqueante
- name: chave_cliente
data_tests:
- relationships:
to: ref('cliente')
field: chave_cliente
config: { severity: error }
- name: situacao_contrato
data_tests:
- accepted_values:
values: ['Em dia', 'Em atraso', 'Liquidado', 'Renegociado']O store_failures: true grava as linhas que falharam em uma tabela de auditoria. É um bom ponto de partida, mas não substitui a quarentena: a tabela de falhas é recriada a cada execução.
Implementação da Quarentena Analítica
Para regras isolantes, a separação acontece dentro do próprio modelo: uma tabela recebe os registros válidos e outra recebe os violadores, com o motivo.
CREATE OR REPLACE TEMPORARY VIEW contrato_avaliado AS
SELECT
c.*,
filter(array(
CASE WHEN cli.chave_cliente IS NULL THEN 'cliente_inexistente' END,
CASE WHEN c.data_vencimento_final < c.data_contratacao THEN 'inconsistencia_temporal' END,
CASE WHEN c.situacao_contrato = 'Liquidado'
AND c.saldo_devedor > 0 THEN 'regra_liquidacao_violada' END,
CASE WHEN c.situacao_contrato IS NULL THEN 'dominio_invalido' END
), m -> m IS NOT NULL) AS motivos_violacao
FROM contrato_candidato c
LEFT JOIN fenix_prd.silver_cadastro.cliente cli USING (chave_cliente);
INSERT INTO fenix_prd.quarentena_credito.contrato_analitica
SELECT *, 'validacao_analitica' AS _etapa, '2.1.0' AS _versao_contrato,
'pendente' AS _status, current_timestamp() AS _quarentenado_em
FROM contrato_avaliado
WHERE size(motivos_violacao) > 0;A diferença essencial entre as duas quarentenas
Aspecto | Quarentena Técnica | Quarentena Analítica |
Pergunta | O registro é estruturalmente utilizável? | O dado faz sentido para o negócio? |
Motivos típicos | Parse inválido, valor incompatível, chave ausente, linha corrompida | Regra violada, domínio inválido, inconsistência analítica, exceções |
Causa provável | Mudança ou falha no sistema de origem | Erro operacional, regra desatualizada, caso de negócio não previsto |
Quem trata | Engenharia de dados | Dono do domínio com analytics engineering |
Resolução comum | Correção na origem e reprocessamento | Ajuste de regra, exceção aprovada ou correção operacional |
Uma observação importante sobre a Quarentena Analítica: às vezes o dado está certo e a regra está errada. Por isso a resolução "exceção aprovada" existe e deve ser registrada, com quem aprovou e por quê.
Zoom no trecho: dois portões, duas quarentenas
Juntando as etapas 7 a 10, o desenho fica simétrico: cada Silver é protegida por um portão de qualidade próprio, e cada portão tem sua própria quarentena.

As linhas tracejadas mostram onde cada correção recomeça: um problema técnico reprocessa a partir da Bronze; um ajuste de regra recalcula só a Silver Analítica, sem tocar na Técnica.
Lado a lado
Dimensão | Silver Técnica | Silver Analítica |
Pergunta que responde | O que o sistema de origem diz? | O que isso significa para o negócio? |
Contrato com | Sistema de origem | Domínio de negócio |
Organização | Por fonte (silver_tec_<fonte>) | Por domínio (silver_<dominio>) |
Grão | O mesmo da origem | Grão de negócio declarado |
Chaves | Natural da origem + substituta determinística | Chave de negócio conformada |
Lê de | Bronze (via validação técnica) | Somente Silver Técnica |
Transformações | Padronização, dedup, hash, CDC, SCD 1 e 2 | Integração, survivorship, tradução, derivação |
Joins entre fontes | Nunca | Sim, é o propósito |
Nomenclatura | snake_case, fiel à origem | Linguagem de negócio, sem siglas |
Portão de qualidade | Validação técnica (antes) | Validação analítica (depois) |
Quarentena | Técnica | Analítica |
Histórico | Técnico (o que a origem dizia e quando) | De negócio (reinterpretação do técnico) |
Materialização | Streaming table, MERGE incremental | Views, materialized views, modelos dbt |
Ferramenta natural | Lakeflow Declarative Pipelines, PySpark | dbt, Databricks SQL |
Muda quando | A origem muda | A regra de negócio muda |
Reprocessa a partir de | Bronze | Silver Técnica |
Dono | Engenharia de dados / plataforma | Analytics engineering + dono do domínio |
Acesso | Restrito | Amplo, com mascaramento |
Consumidores | Silver Analítica, auditoria, conciliação | Gold, ML, Genie, agentes de IA |
Configuração no Databricks
A separação só se sustenta se estiver materializada na plataforma: nomes, propriedades, permissões e contratos diferentes. Sem isso, as duas Silvers viram duas pastas com o mesmo tipo de código.
Unity Catalog: namespaces que dizem o que são
fenix_prd -- catálogo por ambiente (dev, hml, prd)
├── bronze_core_bancario
├── quarentena_core_bancario -- quarentena técnica, por fonte
├── silver_tec_core_bancario -- Silver Técnica, por fonte
├── silver_tec_crm
├── silver_cadastro -- Silver Analítica, por domínio
├── silver_credito
├── quarentena_credito -- quarentena analítica, por domínio
├── controle -- file_manifest, ingestion_registry, watermarks
└── gold_creditoRepare que as quarentenas seguem o mesmo eixo da camada que protegem: a técnica é por fonte, a analítica é por domínio.
Propriedades Delta por camada
Propriedade | Silver Técnica | Silver Analítica | Motivo |
delta.enableChangeDataFeed | true | true se a Gold lê incrementalmente | Permite leitura só do que mudou |
delta.enableDeletionVectors | true | true | MERGE e DELETE sem reescrever arquivos |
CLUSTER BY (liquid clustering) | Chave natural | Colunas de filtro de consumo (data, chave de negócio) | Otimiza o padrão de acesso de cada camada |
delta.logRetentionDuration | Maior (ex.: 90 dias) | Padrão | Time travel para auditoria e conciliação |
Predictive Optimization | Habilitada | Habilitada | OPTIMIZE e VACUUM automáticos |
ALTER CATALOG fenix_prd ENABLE PREDICTIVE OPTIMIZATION;
ALTER TABLE fenix_prd.silver_tec_core_bancario.contrato SET TBLPROPERTIES (
'delta.enableChangeDataFeed' = 'true',
'delta.enableDeletionVectors' = 'true',
'delta.logRetentionDuration' = 'interval 90 days'
);
ALTER TABLE fenix_prd.silver_tec_core_bancario.contrato CLUSTER BY (id_contrato);Permissões e proteção de dados
-- Silver Técnica: acesso restrito ao schema inteiro
GRANT USE SCHEMA, SELECT ON SCHEMA fenix_prd.silver_tec_core_bancario TO `engenharia_dados`;
GRANT USE SCHEMA, SELECT ON SCHEMA fenix_prd.silver_tec_core_bancario TO `auditoria`;
-- Silver Analítica: consumo amplo, com mascaramento de colunas sensíveis
GRANT USE SCHEMA, SELECT ON SCHEMA fenix_prd.silver_cadastro TO `analytics`;
CREATE OR REPLACE FUNCTION fenix_prd.seguranca.mascarar_documento(documento STRING)
RETURN CASE WHEN is_account_group_member('dados_sensiveis') THEN documento
ELSE concat('***', right(documento, 4)) END;
ALTER TABLE fenix_prd.silver_cadastro.cliente
ALTER COLUMN chave_cliente SET MASK fenix_prd.seguranca.mascarar_documento;O mascaramento entra na Silver Analítica porque é ali que o dado começa a circular amplamente. Na Silver Técnica, o controle é feito restringindo o schema inteiro.
Tags, comentários e linhagem
Toda tabela e toda coluna, nas duas camadas, recebem comentário. Tags tornam a camada consultável e alimentam políticas:
ALTER TABLE fenix_prd.silver_tec_core_bancario.contrato
SET TAGS ('camada' = 'silver_tecnica', 'fonte' = 'core_bancario', 'dono' = 'engenharia_dados');
ALTER TABLE fenix_prd.silver_cadastro.cliente
SET TAGS ('camada' = 'silver_analitica', 'dominio' = 'cadastro', 'dono' = 'dominio_cadastro');
ALTER TABLE fenix_prd.silver_cadastro.cliente
ALTER COLUMN email_principal SET TAGS ('pii' = 'email');Com isso, uma consulta a system.information_schema.table_tags responde em segundos quais tabelas são técnicas, quais são analíticas e quem responde por cada uma. A linhagem do Unity Catalog mostra automaticamente o caminho Bronze → Silver Técnica → Silver Analítica → Gold.
Contratos de dados
O contrato é o documento que torna as duas camadas verificáveis. Ele cobre schema, tipos, descrições, nulabilidade, versão e SLA, como no pilar D da arquitetura. A diferença entre as camadas aparece no conteúdo:
# contratos/silver_tec_core_bancario/contrato.yaml
tabela: silver_tec_core_bancario.contrato
camada: silver_tecnica
versao: 1.3.0
dono: engenharia_dados
grao: um registro por id_contrato (estado atual)
chave_natural: [id_contrato]
chave_substituta: sk_contrato (sha2 de sistema_origem + id_contrato)
ordenacao_cdc: sequencia_cdc
sla: { atualizacao: "D+0 até 06:00", latencia_maxima: "2h" }
qualidade:
quarentena: quarentena_core_bancario.contrato_tecnica
taxa_rejeicao_maxima: 0.5%
colunas:
- { nome: id_contrato, tipo: bigint, nulo: false, descricao: Chave natural do contrato no core bancário }
- { nome: valor_contratado, tipo: decimal(18,2), nulo: true, descricao: Valor contratado em reais }
- { nome: situacao, tipo: string, nulo: true, descricao: Código de situação conforme a origem }
---
# contratos/silver_credito/contrato.yaml
tabela: silver_credito.contrato
camada: silver_analitica
versao: 2.1.0
dono: dominio_credito
grao: um registro por numero_contrato
chave_negocio: [numero_contrato]
fontes: [silver_tec_core_bancario.contrato, silver_cadastro.cliente]
regras:
- { id: R01, descricao: Contrato liquidado não tem saldo devedor, severidade: isolante }
- { id: R02, descricao: Totais reconciliam com a Silver Técnica (0,01%), severidade: bloqueante }
sla: { atualizacao: "D+0 até 07:00" }O contrato da Silver Técnica fala de chaves, ordenação e taxa de rejeição. O da Silver Analítica fala de regras, fontes e severidade. Essa diferença de vocabulário é, em si, a melhor prova de que as camadas têm propósitos distintos.
Reprocessamento e observabilidade
Reprocessamento: o maior ganho da separação
A arquitetura prevê cinco modos de reprocessamento. A separação das Silvers define, para cada um, de onde ele parte e até onde ele vai:
Modo | Gatilho típico | Silver Técnica | Silver Analítica |
Backfill | Nova fonte ou nova tabela | Carga do histórico completo a partir da Bronze | Recalculada a partir da Técnica já carregada |
Repair run | Falha em uma etapa de um job | Reexecuta só a tarefa que falhou | Reexecuta só se dependia da tarefa falha |
Por arquivo | Arquivo corrigido na origem ou liberado da quarentena | Reprocessa os registros daquele _arquivo_origem | Recalcula só as chaves afetadas (via Change Data Feed) |
Por período | Correção em uma janela de datas | Reprocessa os lotes do período | Recalcula as partições/janelas do período |
Full refresh controlado | Mudança estrutural ou de regra técnica | Recria a partir da Bronze | Recria a partir da Técnica |
O cenário que mais justifica a separação: mudou uma regra de negócio. Com uma Silver única, você reprocessa desde a Bronze, refaz dedup, CDC e SCD, e torce para chegar no mesmo estado técnico. Com duas Silvers, a Técnica fica intacta e só a Analítica é recalculada, a partir de uma base que já foi conciliada com a origem.
Três cuidados para que o reprocessamento seja seguro:
Idempotência: reprocessar o mesmo lote duas vezes deve produzir o mesmo resultado. Hash técnico, chave substituta determinística e MERGE com condição de ordem garantem isso na Técnica.
Rastreabilidade: todo reprocessamento gera um _id_execucao próprio e um registro em ingestion_registry com o modo, o escopo e o motivo.
Isolamento: em full refresh, escreva em uma tabela nova, compare com a atual (contagens, somas, amostras por hash) e só então troque. Nunca sobrescreva a produção às cegas.
Observabilidade: o que medir em cada Silver
As métricas certas são diferentes porque as falhas prováveis são diferentes.
Métrica | Silver Técnica | Silver Analítica |
Freshness | Atraso entre data_atualizacao máxima e agora | Atraso em relação à Silver Técnica de origem |
Volume | Registros lidos, inseridos, atualizados, excluídos por lote | Registros por domínio e variação contra média móvel |
Qualidade | Taxa de rejeição técnica por regra | Violações por regra de negócio e severidade |
Conciliação | Contagem e soma contra a origem | Totais contra a Silver Técnica |
Duplicidade | Chaves repetidas no lote (antes da dedup) | Chave de negócio duplicada (deve ser zero) |
Custo | DBUs por pipeline (system.billing.usage) | DBUs por modelo e por refresh de materialized view |
No Databricks, as fontes de dados para essas métricas já existem: o event log do Lakeflow traz as métricas de expectations e de fluxo; as system tables trazem custo, linhagem e execuções de jobs; e os SQL alerts fecham o ciclo notificando quem precisa agir.
-- Taxa de rejeição técnica por regra, a partir do event log do pipeline
SELECT
date(timestamp) AS dia,
expectation.name AS regra,
sum(expectation.failed_records) AS rejeitados,
sum(expectation.passed_records) AS aprovados,
round(sum(expectation.failed_records) * 100.0 /
nullif(sum(expectation.failed_records + expectation.passed_records), 0), 3) AS taxa_rejeicao_pct
FROM (
SELECT timestamp,
explode(from_json(details:flow_progress:data_quality:expectations,
'array<struct<name:string,dataset:string,passed_records:bigint,failed_records:bigint>>')) AS expectation
FROM event_log(TABLE(fenix_prd.silver_tec_core_bancario.contrato))
WHERE event_type = 'flow_progress'
)
GROUP BY ALL
ORDER BY dia DESC, taxa_rejeicao_pct DESC;Um painel operacional com uma linha para cada Silver e colunas para freshness, volume, rejeição e conciliação já resolve a maior parte das perguntas de "o dado de hoje está bom?".
Quando separar, quando não separar
Separar tem custo: mais tabelas, mais pipelines, mais armazenamento e mais uma camada para explicar ao time. A separação se paga quando pelo menos dois destes sinais aparecem.
Separe quando
A mesma entidade vem de mais de uma fonte: cliente no core, no CRM e no app.
A origem entrega CDC, snapshots ou deletes: essa complexidade merece uma camada isolada e testada sem ruído de regra de negócio.
As regras de negócio mudam com frequência: reprocessar só a Analítica é muito mais barato e seguro.
Há auditoria ou regulação: setores como financeiro, saúde e seguros precisam provar o que a origem dizia, separado do que o negócio interpretou.
Times diferentes cuidam de cada parte: plataforma na Técnica, domínios na Analítica.
Você vai alimentar IA: agentes, Genie spaces e features de ML precisam de entidades com semântica clara, não de tabelas espelho de ERP.
Não separe quando
Cada entidade tem uma única fonte e as regras de negócio são triviais: uma Silver bem documentada resolve.
O projeto é uma POC ou um laboratório pequeno, e a camada extra atrasaria a entrega sem ganho real.
A fonte já entrega dado conformado e versionado (um SaaS com API limpa): a Silver Técnica seria uma cópia sem valor.
Regra prática: comece sempre com a Silver Técnica quando a origem for transacional. Introduza a Silver Analítica quando surgir a segunda fonte para a mesma entidade ou a primeira regra de negócio reutilizada por mais de um modelo Gold.
Anti-padrões
Regra de negócio na Silver Técnica. Um CASE WHEN de classificação "só para adiantar". Meses depois, ninguém sabe se o valor veio da origem ou foi derivado.
Silver Analítica lendo da Bronze. Pula a validação técnica, reimplementa dedup em cada modelo e produz resultados diferentes para a mesma entidade.
Joins entre fontes na Silver Técnica. Acopla o ciclo de carga de dois sistemas e impede o reprocessamento independente.
Silver Analítica com cara de Gold. Fatos, dimensões e agregações desenhados para um dashboard específico destroem o reuso da camada.
Chave substituta com IDENTITY na Técnica. O primeiro full refresh gera chaves novas e quebra todas as referências downstream.
MERGE sem hash. Cada recarga gera updates vazios, infla o SCD2 e faz a Analítica recalcular registros que não mudaram.
Uma quarentena para tudo. Misturar rejeição técnica e violação de negócio impede saber quem deve agir e qual é a causa.
Descartar em silêncio. expect_or_drop sem fluxo de quarentena e sem métrica faz 3% dos contratos sumirem sem que ninguém perceba.
Copiar o legado mecanicamente. Migrar regras antigas para a Analítica sem revisão transforma erros históricos em contrato.
Duas camadas sem contrato. Se as tabelas não declaram grão, chave, dono e SLA, a separação é só uma pasta a mais.
Conclusão
Silver Técnica e Silver Analítica não são duas cópias do mesmo dado. São dois contratos diferentes, cada um com seu próprio portão de qualidade e sua própria quarentena:
A Silver Técnica tem contrato com o sistema de origem. Ela garante fidelidade, consolidação, histórico e rastreabilidade, protegida pela validação técnica.
A Silver Analítica tem contrato com o negócio. Ela garante significado, integração e reuso, protegida pela validação analítica.
Quando essa fronteira fica clara, cada camada ganha dono, testes, métricas e ritmo de mudança próprios. Uma regra de negócio nova deixa de exigir releitura da origem. Um incidente de ingestão para na Quarentena Técnica em vez de aparecer como queda de KPI. E a Gold passa a ser o que deveria ser desde o início: modelagem dimensional sobre entidades em que já se pode confiar.
Se você está desenhando ou revisando um lakehouse, comece pela pergunta mais simples: para cada tabela Silver que você tem hoje, ela responde "o que o sistema diz" ou "o que isso significa"? Se a resposta for "as duas coisas", você já sabe por onde começar.




Comentários