Um Diff Limpo Não Significa Contrato Completo. Pode Significar Contrato Raso.

TV
Thiago Victorino
6 min de leitura
Um Diff Limpo Não Significa Contrato Completo. Pode Significar Contrato Raso.

Desenvolvimento guiado por spec se apoia em uma suposição que raramente testamos: a de que a spec está completa. Verificamos se o artefato gerado corresponde à spec. Quase nunca verificamos se a spec seria capaz de descrever aquele artefato desde o início.

Nathan Curtis construiu esse teste. Em agosto de 2026 ele publicou What Component Specs Leave Behind, que leva um componente de design system até uma spec, de volta a um componente, e de novo até uma segunda spec. Em seguida faz o diff entre as duas specs. O que sobrevive a esse ciclo é o que o contrato de fato carrega. O que cai fora nunca esteve no contrato, por mais confiante que o documento parecesse.

O resumo do próprio autor, reproduzido com o erro de digitação como publicado: “Turns out, around trip [sic] is a brutal test of a contract. Anything a transform and schema can’t capture gets dropped beaming out, and anything a spec captures too loosely risks loss and differences beaming back.”

A frase trata de tokens de design e propriedades do Figma. Vale para qualquer artefato gerado sob um contrato legível por máquina.

O Ciclo, Exatamente Como Publicado

Seis passos, nesta ordem:

  1. generate de uma spec base a partir de um componente existente.
  2. render de um componente de teste a partir dessa spec.
  3. generate de uma spec de teste a partir do componente de teste.
  4. diff entre a spec base e a spec de teste.
  5. report sobre uma biblioteca inteira.
  6. delete do componente de teste.

O sexto passo é o que torna isso operável em vez de acadêmico. O componente de teste é descartável, então o ciclo roda sobre uma biblioteca inteira sem poluí-la. O artefato sob teste é destruído; o diff é a saída.

O Que o Diff Pegou

Curtis relata classes de falha, sem contagens, e as classes são a parte interessante.

Um código hexadecimal emitido onde havia um token de cor vinculado. O componente renderizado parecia certo e estava errado da única forma que importa em um design system: tinha perdido o vínculo com o token.

Um maxWidth aplicado apenas à última de várias opções. A spec descrevia uma restrição; o render aplicou uma vez.

Uma mudança de backgroundColor e de presença de camada omitida quando as propriedades interagem. selected:true combinado com state:hover produz um comportamento que nenhuma das duas propriedades descreve isoladamente. A spec não tinha vocabulário para a combinação, então a combinação sumiu.

Um ícone decorativo representado como customizável por variante quando não deveria ser. O contrato concedeu uma capacidade que o design não pretendia oferecer.

Padding variando por tamanho conforme o rótulo viesse por um slot ou fosse embutido. Dois caminhos dentro do mesmo componente, um deles sem documentação.

Uma prop BOOLEAN do Figma e uma prop SLOT consolidadas por engano em uma única propriedade de slot anulável. Dois conceitos distintos colapsados em um porque o schema tinha um só lugar para guardá-los.

E o que mais deveria preocupar você: um bug de clipsContent que, nas palavras de Curtis, “silently never worked because it was coded as clipContent”. Uma letra faltando. Sem erro, sem aviso, sem teste falhando. A revisão humana não pegou. O ciclo de ida e volta pegou, porque ele não lê o código: compara o que duas passagens independentes afirmam que o componente é.

A Armadilha em um Resultado Limpo

É aqui que o exercício deixa de ser uma história de design system.

Um contrato que sobrevive perfeitamente ao ciclo pode ser excelente. Também pode estar quase vazio. O ciclo mede fidelidade da transformação. Riqueza do contrato fica de fora da medida. Uma spec que captura um punhado de propriedades vai devolver esse punhado intacto e cala sobre tudo o que jamais mencionou. O diff é silencioso sobre tudo que está fora do próprio vocabulário.

Então um diff limpo é evidência de nada até você saber quanto o contrato estava carregando. Leia o resultado como uma razão que você mesmo precisa estimar: fidelidade sobre cobertura. Fidelidade alta sobre cobertura fina é o formato mais perigoso, porque produz um relatório verde e uma sensação falsa de governança.

O modo de falha é o mesmo de uma suíte que passa em todos os testes que tem enquanto cobre uma fração do código. Ninguém aceitaria esse número sem a segunda metade. Completude de spec costuma ser aceita sem ela.

Limites Que Não São Bugs

Curtis traça uma linha que vale copiar. Algumas perdas no ciclo são defeitos. Outras são limites estruturais permanentes da plataforma, e o movimento honesto é nomeá-las em vez de persegui-las.

Dois limites que ele identifica: a ordem de propriedades customizadas não é exposta pela API para props BOOLEAN, INSTANCE_SWAP, TEXT e SLOT. Vínculos de aspect ratio travado não conseguem carregar largura e altura vinculadas ao mesmo tempo. Os dois estão fora do alcance da spec. Ambos apareceriam em um diff para sempre.

Ele também nomeia um não-objetivo deliberado: o modelo de dados de movimento, que ele decide não suportar porque “few in our field know it well”. É uma decisão de escopo registrada como decisão de escopo, e pertence à documentação da spec para que um diff futuro não a leia como regressão.

Um relatório de ida e volta sem essa classificação degenera em ruído. Toda diferença recorrente precisa de um rótulo: bug a corrigir, limite de plataforma a aceitar, ou escopo excluído de propósito. Curtis registra isso contra os registros de decisão internos do próprio time (ele cita ADR-066 e ADR-069, numeração interna dele, nada de padrão público). O mecanismo importa mais que a numeração. Diferenças que ninguém julgou serão relitigadas a cada execução até as pessoas pararem de ler o relatório.

Onde Mais Isso Se Aplica

Qualquer coisa gerada a partir de um contrato legível por máquina pode passar pelo ciclo, e eu não vi nenhum desses contratos ser testado quanto ao que descarta em silêncio.

Um schema OpenAPI que gera um cliente. Gere o cliente, gere um schema a partir do cliente, faça o diff. Opcionalidade, unions discriminadas e semântica de header são onde eu olharia primeiro.

Um módulo de infraestrutura renderizado a partir de um arquivo de variáveis. Renderize, extraia de novo, compare. Defaults que só existem no provider são os que eu esperaria não ver voltar.

Um prompt ou uma definição de tool que governa um agente. Este é o caso mais próximo de casa. Se o contrato do seu agente é um schema JSON mais uma descrição, o ciclo pergunta se um segundo leitor, tendo apenas o schema, produziria a mesma tool. Se divergir, a diferença é exatamente o comportamento que seus evals não conseguem explicar.

Já argumentamos que design systems são infraestrutura de governança, que agentes funcionam como detectores de drift contra um sistema presumido correto, e que um agente que escreve o sistema não é o mesmo que um agente que o revisa. Este ciclo inverte os três. Aqueles testavam conformidade ao contrato. O ciclo de ida e volta testa o contrato.

Faça Isso Agora

Pegue o componente, endpoint ou definição de tool mais usado que você tem. Um só, sem envolver a biblioteca inteira.

Gere uma spec a partir dele com a ferramenta que você tiver. Entregue essa spec, e apenas ela, para uma sessão nova de agente sem acesso ao original. Peça o artefato. Gere uma spec a partir do resultado. Compare as duas.

Depois leia o diff duas vezes. A primeira leitura encontra os bugs. A segunda faz a pergunta difícil: de tudo que importa nesse artefato, quanto qualquer uma das duas specs chegou a mencionar? Anote esse número como estimativa, ao lado do diff. Um diff limpo sobre um contrato raso é o resultado que você está tentando detectar, e é justamente o que se parece com sucesso.


Fontes

A Victorino ajuda times de engenharia a testar se suas specs realmente carregam o contrato de que os sistemas gerados dependem: contato@victorino.com.br | www.victorino.com.br

Todos os artigos do The Thinking Wire são escritos com o auxílio do modelo LLM Opus da Anthropic. Cada publicação passa por pesquisa multi-agente para verificar fatos e identificar contradições, seguida de revisão e aprovação humana antes da publicação. Se você encontrar alguma informação imprecisa ou deseja entrar em contato com o editorial, escreva para editorial@victorino.com.br . Sobre o The Thinking Wire →

Se isso faz sentido, vamos conversar

Ajudamos empresas a implementar IA sem perder o controle.

Agendar uma Conversa