


Corrija a causa raiz em uma base de código grande e mantenha a API pública compatível
Use quando uma IA alterar uma base de código grande e em camadas. Mantém curtos os logs de build, rastreia os bugs até a causa de origem, revisa o próprio diff em busca de helpers que só escondem problemas e escreve um pull request claro.
Para usar estas regras de IA
## Mantenha curtos os logs de build e rode o formatador e os testes antes de cada commit
- Ao compilar, redirecione toda a saída da build para o dispositivo nulo e execute o mesmo comando novamente em modo verboso somente se ele falhar, para que uma build bem-sucedida não gaste tokens com logs. Por exemplo: `build-command >/dev/null 2>&1 || build-command`.
- Prefira dependências armazenadas em cache local a buscas pela rede, e ative um cache de build ou de compilador quando disponível para acelerar as recompilações incrementais.
- Em builds longas, não supervisionadas ou conduzidas por agentes, desative diálogos modais de aborto ou de asserção no momento da configuração, para que a execução não fique travada esperando por um humano.
- Execute o formatador antes de cada commit e use seu modo somente-verificação para conferir sem modificar arquivos; código que não segue o estilo do projeto força idas e vindas de revisão evitáveis.
- Execute o conjunto de testes a partir da raiz do repositório e adicione testes de regressão como arquivos dentro do diretório de testes do projeto. Quando não houver GPU ou hardware especial disponível, use modos de teste em CPU ou interpretador em vez de pular a cobertura.
- Em ambientes com shells cruzados, por exemplo um shell Unix chamando ferramentas do host, adicione a extensão de executável correta para que o binário do host pretendido seja executado, e não um de plataforma errada.
## Corrija a causa de origem em vez de adicionar verificações de proteção
- Busque uma representação que seja correta e robusta por construção, mesmo quando isso significar um retrabalho maior do que o menor diff possível.
- Corrija causas raízes, não sintomas. Quando um bug aparece em uma fase tardia, como a geração de saída, a causa geralmente está a montante: uma transformação anterior, uma legalização, uma especialização, um rebaixamento (lowering) ou a própria representação dos dados. Rastreie até lá e corrija ali.
- Questione toda mudança antes de mantê-la: por que ela é necessária, qual teste falha sem ela, e essa é a correção certa ou o problema está sinalizando que a representação está falha? Se você não consegue apontar um teste que falha sem a mudança, ela provavelmente não deveria existir.
- Não mascare. Uma guarda, verificação de nulo ou caso especial que disfarça uma estrutura malformada esconde um bug de representação, e uma guarda que nunca é acionada com entradas corretas é código morto. Torne a representação correta para que os consumidores a jusante permaneçam simples.
- Questione o formato da entrada. Sempre que você tratar um formato específico de entrada, pergunte-se se esse formato em si está correto, ou se o produtor a montante deveria ser corrigido; trate-o localmente apenas quando o formato for, de fato, uma entrada válida.
- Prefira a representação correta à menor distância de edição. Se duas formas de superfície deveriam ser equivalentes, modele-as de forma idêntica, e acesse dados de chave-valor conceitualmente não ordenados pela chave ou papel, e não por posição ou índice.
- Mantenha um registro de trabalho ao longo de toda a tarefa: o problema com um exemplo motivador, bloqueios, como uma correção se propaga em cascata para a próxima, a correção escolhida e por que ela é baseada em princípios, e as alternativas rejeitadas. Condense isso na descrição da mudança e mantenha-o fora do código commitado.
## Revise seu diff em busca de helpers que só escondem um design ruim
- Antes de finalizar uma mudança não trivial, revise o diff em busca de sinais de que ela está compensando uma representação ruim, e trate esses padrões como sinais de alerta até que você consiga provar que eles pertencem a essa camada.
- Funções auxiliares personalizadas de equivalência semântica, como novas funções recursivas de são-equivalentes ou corresponde, costumam significar que duas representações alternativas foram deixadas sobreviver; primeiro pergunte por que um caminho existente de canonicalização, substituição ou igualdade ainda não as torna idênticas.
- Crescimento não auditado de funções auxiliares: trate toda nova função auxiliar, fallback ou função no estilo tentativa como alvo de revisão, especialmente uma que existe apenas para fazer um único teste que falha passar, ou que reimplementa parte de um mecanismo já existente.
- A reconstrução de sintaxe a partir de semântica, isto é, reconstruir a sintaxe de superfície a partir de dados semânticos já verificados, geralmente significa que o produtor preservou a representação errada; o valor semântico verificado deveria ser a fonte da verdade.
- A redescoberta de contexto por meio de percurso de grafo, percorrendo cadeias de operandos, referências ou posse para recuperar argumentos, chaves ou pais, geralmente é um reparo a jusante; em vez disso, construa a forma canônica no produtor.
- Correções do lado do consumidor: fases tardias não deveriam corrigir formatos malformados vindos de fases anteriores, e detalhes de representação fixados no código (casos especiais para subclasses específicas, nomes mágicos, índices de argumentos ou ordem de entrada) exigem um invariante forte e geralmente pertencem a um limite de construção canônica.
- Tratamento silencioso de formatos impossíveis: uma guarda que retorna um valor padrão para um formato fora do contrato esconde bugs; declare (assert) o formato impossível em vez de aceitá-lo silenciosamente.
- Comece a revisão com um inventário de funções auxiliares suspeitas, listando cada nova função, com qual mecanismo existente ela se sobrepõe e qual teste falha sem ela. Para cada mudança sinalizada, identifique o formato exato de entrada e seu produtor, decida se o formato é canônico ou uma alternativa acidental, tente primeiro a correção do lado do produtor, identifique a fonte da verdade já existente, e faça o teste de reversão: remova a mudança, execute o menor teste que falha e rastreie a quebra real. Não mantenha uma mudança sinalizada apenas porque ela faz os testes passarem.
## Escreva comentários com exemplos e mantenha cada informação em um só lugar
- Escreva comentários de funções em frases completas: primeiro declare o que a função faz, depois por que ela existe, se isso não for óbvio, e inclua um exemplo concreto para comportamentos não triviais, em vez de um fragmento curto demais.
- Use exemplos em tom de conversa nos comentários e explicações. Prefira algo como "Considere este exemplo:" com código real, e então descreva passo a passo o que acontece, qual etapa (pass) cria o formato, qual invariante o código local preserva e qual consumidor depende dele, em vez de usar rótulos abstratos como substituto de uma explicação.
- Reutilize antes de escrever, e depois extraia lógica não trivial para uma função auxiliar nomeada e documentada. Procure primeiro nos utilitários compartilhados; quando a lógica for genuinamente nova, dê a ela um nome que revele sua intenção e um comentário de documentação, em vez de enterrar um cálculo de várias etapas dentro de um bloco em linha.
- Mantenha uma única fonte da verdade e remova código morto após uma refatoração: mapeie ou classifique uma determinada coisa em exatamente um lugar, e quando uma mudança tornar um branch (ramo condicional) ou função auxiliar inalcançável, remova-o em vez de deixá-lo para trás.
- Mantenha uma única representação canônica por valor e declare (assert) o invariante. Uma segunda representação do mesmo valor lógico quebra a igualdade, a identidade e a deduplicação; faça a asserção no ponto de construção quando um invariante garantir que uma determinada forma nunca é produzida para certas entradas.
- Falhe de forma explícita diante de entradas fora do contrato. Quando uma função auxiliar é válida apenas para um conjunto restrito de entradas, faça a asserção sobre qualquer coisa fora desse conjunto, em vez de retornar silenciosamente um valor padrão.
## Escreva o pull request em cinco partes e inclua testes de regressão
- Formate o código e, em seguida, classifique a mudança como não disruptiva por padrão, ou disruptiva quando ela alterar uma interface binária ou o comportamento da linguagem.
- Inclua testes de regressão que teriam falhado antes da correção.
- Escreva a descrição em uma estrutura fixa de cinco partes: motivação (o problema com um exemplo concreto motivador), solução proposta (a abordagem e por que ela é a baseada em princípios), resumo da mudança (uma lista dos arquivos ou áreas afetadas e o que cada uma faz), conceitos e vocabulário (um glossário curto apenas dos termos específicos da base de código ou sutis dos quais o relatório depende, não de conceitos básicos já conhecidos) e um relatório do processo.
- No relatório do processo, explique cada mudança com uma razão lógica. Para um problema em cascata, apresente o teste que o motivou e um rastro no código nomeando as funções exatas envolvidas, não apenas uma descrição. Para qualquer mudança que proteja ou trate como caso especial um formato de entrada, declare se esse formato é uma entrada válida ou se o seu produtor deveria ter sido corrigido, para que um revisor possa confirmar que a correção está na camada certa.
- Escreva para um revisor que não tem o seu contexto: comece a partir de um exemplo concreto, inclua o trecho de código relevante em vez de apenas citar o nome de um tipo ou função, e explique os passos em ordem.
## Acrescente ao final de enums e interfaces para não quebrar a API pública nem a ABI
- Trate toda mudança em um header de API pública como algo que precisa preservar a compatibilidade binária e de código-fonte para chamadores já compilados contra uma versão anterior.
- Enums: nunca insira um novo enumerador no meio de um enum existente, porque a inserção desloca todos os valores posteriores e quebra silenciosamente chamadores que armazenaram ou compararam esse valor. Adicione novos enumeradores imediatamente antes do membro de contagem final ou sentinela, com um valor sequencial explícito, e, para aposentar um enumerador, renomeie-o para uma forma que marque remoção, mantendo seu inteiro original — nunca reutilize um valor aposentado.
- As tabelas de métodos virtuais em interfaces no estilo COM têm um layout fixado pela ordem de declaração; portanto, nunca reordene métodos virtuais, nunca altere a assinatura ou a convenção de chamada de um método, nunca insira um novo método no meio (adicione ao final, antes da chave de fechamento) e nunca remova um método: substitua seu corpo por um stub de não implementado e mantenha a declaração.
- Evite estender uma interface pública existente diretamente quando os clientes podem implementá-la ou consultá-la por identificador; prefira adicionar uma nova interface derivada ou versionada, com seu próprio identificador, mantendo a original com suporte para os chamadores existentes.
