
Seu agente de codificação IA continua refazendo o bug que você já corrigiu. Aqui está a solução.
nas últimas versões, o selvedge tem sido uma coisa somente para escrita. um agente de IA edita uma coluna, chama log_change, e o raciocínio é capturado em um pequeno arquivo SQLite sob .selvedge/ ao lado do seu código. útil, mas unidirecional. o agente escreveu na loja e nunca mais olhou para isso novamente.
a versão v0.3.7 é a versão onde isso muda. há uma nova ferramenta MCP chamada prior_attempts, e o objetivo dela é que o agente a chama antes de mudar algo — não depois. antes de editar users.email, o agente pergunta ao selvedge: o que aconteceu da última vez que alguém tocou nisso? quem tentou o quê, quando e por que foi revertido?
esta é a versão que define a marca, então deixe-me explicar por que foi construída da maneira que foi.
o fluxo padrão costumava ser unidirecional
veja como o selvedge parecia na versão v0.3.6. um agente refatora users.email, e ao sair chama log_change com uma string de raciocínio — "apertou o validador de email para rejeitar endereçamento por mais, conforme o pedido da equipe de faturamento." esse raciocínio vai para a loja. mais tarde, um humano executa selvedge blame users.email a partir da CLI e lê de volta.
essa é a mesma postura que todas as ferramentas de atribuição de código têm. git blame, AgentDiff, Origin, todas elas. o raciocínio é capturado-para-lido. a captura é um evento em um momento; a leitura é um ato separado e assíncrono por um ator diferente — geralmente uma pessoa, geralmente semanas depois, geralmente porque algo já quebrou.
para uma base de código escrita por humanos, isso é aceitável. as pessoas carregam contexto entre as sessões. elas lembram "ah certo, tentamos isso em março." a trilha de auditoria é um backup para a memória, não a memória em si.
prior_attempts é o primitivo de pergunta
então a v0.3.7 adiciona a ferramenta que faz a pergunta. é um modelo pull — o agente a chama, o selvedge não empurra. dada uma descrição ou um entity_path, ela retorna eventos de mudança anteriores no mesmo caminho (ou na mesma forma) com seu raciocínio, seu tipo de mudança e um resultado inferido.
> prior_attempts(entity_path="users.email")
2 tentativas anteriores em users.email:
[2026-03-14] renomear -> users.email_address (revertido em 2026-03-17)
raciocínio: "renomeado para consistência com users.phone_number"
resultado: revertido — a junção de reconciliação de faturamento foi chaveada no
nome da coluna literal; a sensibilidade a maiúsculas quebrou o trabalho noturno
[2026-01-22] alterar -> apertar tipo para citext (abandonado)
raciocínio: "comparação sem distinção de maiúsculas na camada db"
resultado: nenhum commit de acompanhamento; supercedido pela validação na camada de app
o agente agora tem o contexto que march-mason anotou. e faz a coisa que toda a versão foi construída para permitir: muda o plano. não renomeia a coluna. mantém users.email, endurece o validador na camada de app em vez disso, e anota em seu próprio log_change que verificou as tentativas anteriores primeiro. o ciclo se fecha.
nenhuma chamada LLM acontece em nenhum lugar disso, a propósito. a saída é modelada — o selvedge a monta de forma determinística a partir das linhas no SQLite. essa é uma regra rígida no núcleo: sem saltos de modelo, sem chave de API, sem rede, sem não-determinismo que seja miserável de testar. prior_attempts é uma consulta e um modelo de string, nada mais.
por que o orçamento de confiança é inegociável
esta é a decisão de design que eu mais hesitei. prior_attempts retorna resultados de alta confiança apenas por padrão.
a maneira como inferimos "resultado" na v0.3.7 é por proximidade: um adição seguida de perto por uma remoção da mesma entidade é lida como "tentou e retirou." isso é uma heurística, e heurísticas têm uma cauda barulhenta. então cada resultado carrega um campo de confiança — proximity_high ou proximity_low — e a resposta padrão lhe dá apenas proximity_high. se você quiser a cauda longa barulhenta, você tem que pedir explicitamente com min_confidence="proximity_low".
a razão é o orçamento de confiança, e você só tem uma chance. no momento em que prior_attempts entrega a um agente um falso positivo que parece confiante, o agente aprende que a ferramenta é barulho e começa a ignorá-la — e uma ferramenta que o agente ignora está morta. um resultado vazio é recuperável. um resultado errado não é. então o padrão é ajustado para preferir retornar nada em vez de retornar algo errado.
essa é a mesma disciplina dos códigos de saída de dois níveis do selvedge verify da v0.3.5: construa o piso estrito primeiro, depois dê ao chamador um botão para relaxá-lo se quiser. padrões conservadores são o que mantêm o mecanismo honesto. o classificador preciso vem depois — a v0.3.11 envia tipos de mudança explícitos reject e revert para que o nível de alta confiança fique mais preciso sem que a API mude.
a fundação da entidade que teve que ser enviada na mesma versão
você não pode enviar uma ferramenta de pesquisa quando ./src/auth.py::login e src/auth.py::login armazenam como duas entidades diferentes. se o fizer, o problema de recuperação se disfarça como "prior_attempts não encontrou nada", o agente prossegue confiante, e a ferramenta o desorientou ativamente — pior do que não existir. então a canonização teve que ser implementada primeiro, dentro da mesma versão.
canonização na escrita é determinística e entediante de propósito: remove um ./ inicial, colapsa //, normaliza separadores para /, remove espaços em branco. um gargalo que tanto o caminho de escrita do MCP quanto a CLI passam, para que nada escreva um caminho não canônico após esta versão.
a única decisão que vale a pena destacar: o caso é preservado, deliberadamente. sistemas de arquivos discordam — macOS e Windows são insensíveis a maiúsculas por padrão, a maioria dos hosts Linux é sensível a maiúsculas. se o selvedge silenciosamente convertesse tudo para minúsculas, colapsaria duas entidades que são genuinamente distintas em um host sensível a maiúsculas. então ele preserva o caso, e selvedge doctor cresce uma linha de aviso que sinaliza caminhos irmãos que diferem apenas pelo caso, para que você descubra em vez de obter uma mesclagem silenciosa.
para bancos de dados existentes, há selvedge migrate-paths. é --dry-run por padrão — você tem que passar --apply para escrever qualquer coisa — e a execução a seco imprime um relatório de colisões mostrando quais caminhos pré-canonizados convergiriam para o mesmo valor. você pode olhar para a mesclagem antes que aconteça. é idempotente, e cada execução insere uma linha de auditoria em uma nova tabela path_migrations para que a operação permaneça visível.
e o objetivo explícito não é, porque isso surge toda vez: sem analisador de código, sem AST. o selvedge não lê seu código-fonte e extrai entidades. ele armazena o que o agente lhe diz, canonizado e consultável. o trabalho de AST é específico de linguagem, arrasta uma pilha de dependências e luta contra a regra de núcleo sem dependências que mantém a instalação em três dependências. é uma linha que estou mantendo.
o que a mudança do bloco de prompt altera
uma nova ferramenta MCP que ninguém chama não tem valor, e os agentes não descobrem espontaneamente ferramentas de consulta. então o ciclo é uma linha na instrução do agente. selvedge prompt agora lidera com:
Antes de editar uma entidade, chame
prior_attemptsnela.
essa é a primeira instrução agora, não uma nota de rodapé sob a orientação de log_change. é o que transforma agentes somente de escrita em agentes de leitura-antes-de-escrever. sem isso, toda a versão é uma ferramenta sentada em uma lista que nunca é acionada.
os usuários existentes recebem a mudança de forma limpa porque o bloco de prompt é cercado por sentinelas (o <!--
A implementação da ferramenta prior_attempts pode transformar a maneira como as empresas brasileiras gerenciam suas bases de código, permitindo que agentes de IA aprendam com tentativas anteriores. Isso pode resultar em menos bugs e maior eficiência no desenvolvimento de software.

