top of page

Simon Willison Enfrentou Falhas de CI com Ruff v0.16.0. Os Padrões Haviam Mudado

Simon Willison viu vários jobs de CI falharem depois que o Ruff v0.16.0 ampliou suas regras de lint padrão de 59 para 413. Sua dependência de desenvolvimento do Ruff, sem versão fixada, incorporou silenciosamente a nova versão a projetos Python já existentes.

A Astral lançou a versão em 23 de julho de 2026. Dois dias depois, Willison descreveu como a atualização chegou aos seus builds sem uma atualização deliberada. As falhas transformaram uma versão de linter em um alerta prático sobre gestão de dependências.

O conflito central não é entre linting mais rígido e código mais fraco. É entre a segurança sem configuração cada vez maior do Ruff e a estabilidade que desenvolvedores esperam de repositórios inalterados. Essa tensão importa em todo lugar onde a CI instala as ferramentas de desenvolvimento mais recentes disponíveis a cada execução.

Ruff v0.16.0 Mudou o Significado de “Padrão”

A mudança mais consequente do Ruff v0.16.0 não é um novo comando. É uma definição muito mais ampla do que projetos sem configuração devem considerar um erro.

Ruff é um linter e formatador Python escrito em Rust. Um linter analisa o código-fonte em busca de erros, padrões suspeitos e problemas de estilo selecionados sem executar o programa.

Antes desta versão, o Ruff ativava 59 regras quando um projeto não fornecia uma seleção explícita de lint. A versão 0.16.0 ativa 413 regras na mesma condição, segundo o guia de migração da Astral.

Isso representa um aumento de 354 verificações ativas. Também significa que uma instalação padrão do Ruff agora avalia quase sete vezes mais regras do que antes.

O catálogo ao redor também cresceu. O Ruff suportava 708 regras quando seus padrões mudaram pela última vez na versão 0.1.0. A Astral afirma que a coleção atual contém 968 regras.

Os padrões antigos selecionavam principalmente partes de Pyflakes e pycodestyle. Os projetos podiam adotar o Ruff sem precisar tomar imediatamente decisões detalhadas sobre suas muitas famílias de regras integradas.

Essa base conservadora ajudou o Ruff a se encaixar em repositórios existentes. Mas também criou uma distância cada vez maior entre o que a ferramenta sabia e o que ela reportava automaticamente.

A Astral reduziu grande parte dessa distância na versão 0.16.0. Os novos padrões recorrem a famílias adicionais, incluindo flake8-bugbear, pyupgrade e a própria categoria RUF do Ruff.

Flake8-bugbear concentra-se em prováveis bugs e padrões de design questionáveis. Pyupgrade identifica padrões de sintaxe e da biblioteca padrão que podem ser modernizados para a versão de Python suportada por um projeto.

A lista de regras padrão agora inclui verificações capazes de expor problemas de sintaxe e erros imediatos em tempo de execução. Não se trata apenas de preferências sobre espaçamento ou nomenclatura.

Essa distinção explica por que falhas de CI do Ruff podem merecer atenção. Alguns novos relatórios revelam defeitos que antes passavam apenas porque o Ruff não ativava automaticamente o detector relevante.

Outros relatórios tratarão de manutenibilidade, modernização ou padrões que uma equipe aceita intencionalmente. Um conjunto padrão maior não pode conhecer os requisitos de compatibilidade ou as convenções de design de cada repositório.

Portanto, o Ruff v0.16.0 muda duas coisas ao mesmo tempo. Ele aumenta a detecção automática de defeitos e transfere mais decisões de política para a primeira atualização após 23 de julho.

A versão também passa a formatar, por padrão, blocos de código Python dentro de arquivos Markdown. Os blocos delimitados compatíveis incluem python, py, python3, py3, pyi e pycon.

Esse comportamento importa para repositórios que contêm documentação, tutoriais ou notebooks Quarto. Uma verificação de formatação agora pode identificar alterações fora dos arquivos .py convencionais.

As notas de lançamento do Ruff também descrevem novos comentários de supressão e uma saída de diagnóstico mais rica. Essas melhorias ajudam desenvolvedores a lidar com as descobertas adicionais quando elas surgem.

A mudança de escopo continua sendo o principal evento de migração. Um comando que se comportava de forma previsível na semana passada pode retornar hoje um código de saída diferente de zero contra código-fonte idêntico.

Por Que as Falhas de CI de Simon Willison Importam

A experiência de Simon Willison mostra como uma atualização de ferramenta de desenvolvimento pode mudar a política efetiva de um repositório sem modificar o próprio repositório.

Willison é um desenvolvedor independente e escritor conhecido por projetos envolvendo Python, ferramentas de dados e IA generativa. Ele também cocriou o framework web Django no início de sua carreira.

Em 25 de julho, Willison escreveu que seus “vários jobs de CI” haviam começado a falhar. Ele atribuiu as falhas aos novos padrões do Ruff e a uma dependência de desenvolvimento "ruff" sem versão fixada.

Seu relato sobre Ruff dá à versão uma perspectiva concreta de usuário. O código do repositório não havia necessariamente regredido, mas seu ambiente de validação havia mudado sob seus pés.

Um job de CI, ou integração contínua, executa verificações automatizadas sempre que desenvolvedores propõem ou mesclam alterações. As equipes dependem de resultados consistentes para decidir se o código pode ser aceito com segurança.

Se um job instala ruff sem uma restrição de versão, o resolvedor de pacotes pode selecionar a versão mais recente disponível. O build seguinte pode então aplicar um comportamento que nenhum responsável revisou explicitamente.

Esse modo de falha é fácil de minimizar porque o Ruff normalmente é uma dependência de desenvolvimento. Em geral, ele não é distribuído dentro da aplicação que atende usuários.

Ainda assim, dependências de desenvolvimento controlam se o software pode avançar pelo pipeline de entrega. Um novo código de saída de linter pode bloquear um pull request, interromper uma versão ou consumir horas de investigação.

O incidente também expõe uma distinção enganosa entre dependências de runtime e ferramentas. Pacotes de runtime afetam o que o software implantado faz, enquanto ferramentas afetam se os desenvolvedores conseguem implantá-lo.

Ambos podem introduzir mudanças operacionais. Eles apenas atuam em pontos diferentes do sistema.

A experiência de Willison é especialmente útil porque as regras ampliadas do Ruff funcionavam como lançadas. As falhas não exigiram um pacote corrompido, um registro comprometido ou um instalador defeituoso.

A ferramenta foi instalada com sucesso. Ela inspecionou corretamente o projeto sob sua nova política. A CI falhou porque essa política diferia daquela em que o repositório havia confiado implicitamente.

Isso torna o caso um problema de reprodutibilidade. Um build ou verificação reproduzível deve produzir resultados equivalentes a partir do mesmo código-fonte e das mesmas entradas declaradas.

“Ruff mais recente” não é uma entrada estável. É uma solicitação móvel, cujo significado depende de quando um gerenciador de pacotes a resolve.

Lockfiles e restrições exatas podem tornar essa entrada explícita. Serviços de atualização podem então propor upgrades controlados, permitindo que os responsáveis inspecionem novos diagnósticos antes de mesclar a mudança de versão.

A lição vai além do Ruff. Formatadores, verificadores de tipos, executores de testes, geradores de documentação e scanners de segurança podem todos revisar seus padrões entre versões.

Um repositório com bibliotecas de aplicação fixadas, mas ferramentas de desenvolvimento flutuantes, continua apenas parcialmente reproduzível. Seu comportamento em produção pode permanecer fixo enquanto seu caminho até a produção muda.

Essa preocupação é particularmente relevante para sistemas automatizados de programação. Agentes frequentemente executam verificações de repositório, interpretam suas saídas e modificam código até que todas as barreiras sejam aprovadas.

Se as ferramentas por trás dessas barreiras mudam inesperadamente, o agente enfrenta um alvo móvel. Ele pode gerar edições desnecessárias ou suprimir descobertas sem entender por que elas apareceram.

Equipes que constroem uma base de conhecimento de engenharia pesquisável podem preservar decisões de atualização junto à configuração e ao histórico de CI. Esse contexto ajuda futuros responsáveis a distinguir política intencional de desvio acidental.

Simon Willison Expôs o Novo Equilíbrio do Ruff

Os padrões mais amplos do Ruff melhoram a cobertura na primeira execução, mas transferem o trabalho de migração para projetos que tratavam uma configuração omitida como um contrato estável.

A posição da Astral é direta. O Ruff acumulou centenas de verificações enquanto sua seleção padrão permaneceu congelada, deixando diagnósticos importantes inativos para usuários sem configuração.

A seleção antiga remontava ao Ruff v0.1.0. Desde então, o catálogo de regras aumentou em 260, de 708 para 968.

Manter apenas 59 verificações ativadas significava que a experiência sem configuração do Ruff representava uma parcela cada vez menor de suas capacidades. Novos usuários poderiam supor que o padrão era mais abrangente do que realmente era.

A versão aborda essa discrepância. Agora, desenvolvedores podem descobrir erros de sintaxe, riscos de runtime, oportunidades de modernização e construções suspeitas sem antes estudar centenas de códigos de regra.

Isso é valioso para projetos pequenos. Também beneficia novos repositórios que desejam uma cobertura sensata antes que os responsáveis desenvolvam uma política detalhada de linting.

A expectativa oposta é igualmente razoável. Padrões são frequentemente tratados como comportamento de produto, especialmente quando a documentação apresenta uma ferramenta como utilizável sem configuração.

Desenvolvedores que omitem lint.select podem acreditar que estão escolhendo a base mantida do Ruff. Antes da versão 0.16.0, eles também dependiam de essa base permanecer estável entre atualizações.

A Astral mudou a base porque deixá-la intacta tinha seu próprio custo. Projetos podiam passar no Ruff enquanto continham erros que o binário instalado já sabia detectar.

Portanto, a troca não é entre segurança e conveniência. É entre proteção automática mais ampla e previsibilidade nas atualizações.

Um padrão mais restrito reduz surpresas durante atualizações, mas oculta mais descobertas de novos usuários. Um padrão mais amplo revela mais defeitos, mas pode interromper pipelines estabelecidos.

O Ruff v0.16.0 escolhe uma proteção mais forte para a próxima execução. Projetos que desejam o contrato anterior agora precisam registrar essa preferência explicitamente.

A Astral fornece uma configuração direta de compatibilidade:

A tabela exata pode variar quando a configuração reside em um ruff.toml independente. A decisão importante é a seleção explícita de regras, não o nome do arquivo.

Essa configuração restaura as famílias de regras padrão anteriores. Ela dá às equipes margem de manobra sem forçá-las a fixar indefinidamente a versão 0.15.

No entanto, restaurar o comportamento antigo deve ser uma etapa de migração, e não uma rejeição automática de cada nova verificação. Algumas falhas podem identificar bugs que valem a pena corrigir imediatamente.

Uma atualização cuidadosa começa capturando a saída completa de diagnóstico. Os responsáveis podem então agrupar as descobertas por código de regra, gravidade, segurança da correção e impacto de compatibilidade.

Regras que expõem problemas definitivos de sintaxe ou runtime merecem prioridade. Descobertas de modernização mecânica podem ser revisadas separadamente, de preferência em commits focados.

Verificações orientadas por política exigem julgamento da equipe. Um padrão pode ser válido para arquivos gerados, convenções de framework, módulos de compatibilidade ou APIs públicas que não podem mudar casualmente.

O Ruff oferece ignoramentos por arquivo e supressões direcionadas para esses casos. A versão 0.16.0 adiciona os comentários ruff: ignore e ruff: file-ignore ao comportamento noqa já existente.

A supressão direcionada costuma ser mais fácil de auditar do que uma exclusão ampla. Ela registra onde uma regra não se aplica e pode incluir um motivo para futuros responsáveis.

Ainda assim, supressões podem se tornar uma poluição visual quando centenas de violações existentes aparecem de uma vez. Uma seleção de regras para todo o projeto pode ser mais honesta até que os responsáveis programem uma limpeza deliberada.

A resposta correta depende da maturidade do repositório. Um novo projeto pode adotar imediatamente a base mais ampla, enquanto uma grande base de código legada pode precisar de adoção em etapas.

É por isso que mudanças nos padrões têm um peso incomum. Elas aplicam um julgamento de nível de produto a projetos com históricos e restrições radicalmente diferentes.

Os Novos Padrões São Apenas Parte da Migração

As equipes que corrigirem a primeira leva de diagnósticos ainda precisam revisar a formatação de Markdown, a saída legível por máquinas e o comportamento de supressão.

O Ruff v0.16.0 passa a incluir blocos de código Python em Markdown no alcance normal de seu formatador. Isso pode alterar READMEs, páginas de documentação e arquivos de publicação no estilo de notebooks.

O formatador reconhece strings de informação comuns do Python associadas a blocos de código delimitados. Ele trata pyi como código de stub e pycon como uma sessão interativa de Python.

Usuários do Quarto também podem formatar blocos marcados com formatos como {python}. Projetos que usam arquivos .qmd talvez precisem de um mapeamento de extensão antes que o Ruff os inclua.

Esse recurso alinha exemplos da documentação ao formatador do código-fonte. Isso reduz a chance de exemplos copiados usarem formatação desatualizada ou inconsistente.

Ele também pode gerar falhas inesperadas de CI quando ruff format --check antes examinava apenas arquivos-fonte convencionais. Responsáveis pela documentação podem encontrar políticas do Ruff pela primeira vez.

Os projetos podem excluir Markdown com extend-exclude, se necessário. Também podem usar comentários de supressão de formatação em torno de regiões selecionadas.

A decisão deve refletir se as amostras de código são orientações executáveis ou material explicativo cuidadosamente organizado. A formatação automatizada ajuda a primeira categoria de forma mais consistente do que a segunda.

A renderização dos diagnósticos também mudou. O Ruff agora mostra diffs sugeridos na saída normal de check e format --check.

Antes, os desenvolvedores podiam solicitar um diff separadamente. A nova saída completa mantém diagnósticos e alterações propostas juntos, facilitando a interpretação de uma verificação com falha.

Para provedores de CI, format --check agora oferece suporte a formatos de saída usados para anotações do GitHub e GitLab. Um problema de formatação pode aparecer diretamente na linha afetada em uma revisão de código.

Consumidores automatizados precisam de mais atenção. Vários campos da saída JSON do Ruff agora podem ser null em vez de conter localizações de preenchimento.

Os campos afetados incluem filename, location, end_location e as localizações correspondentes dentro das edições de correção. Consumidores que pressupõem que toda localização é um objeto ou uma string podem falhar.

Essa é uma pequena mudança incompatível para a maioria dos usuários. Ela é mais importante para equipes que analisam a saída do Ruff em dashboards, bots de revisão ou sistemas personalizados de qualidade.

Portanto, um pipeline pode falhar em três camadas após a atualização. O Ruff pode encontrar uma nova violação, a formatação pode se estender a um novo tipo de arquivo ou um analisador de saída pode rejeitar campos anuláveis.

Tratar toda falha como “mais regras de lint” pode fazer com que a causa real passe despercebida. Os mantenedores devem identificar qual camada mudou antes de editar o código da aplicação.

O novo formato de supressão também merece uma revisão de política. Um ruff: ignore[F401] no fim da linha funciona como um noqa direcionado para esse diagnóstico.

Um comentário anterior pode suprimir descobertas na próxima linha lógica. Isso é útil para cabeçalhos de funções em múltiplas linhas, nos quais o problema relatado não se encaixa bem ao lado do token relevante.

A supressão para todo o arquivo está disponível por meio de ruff: file-ignore. Ela pode incluir uma justificativa, oferecendo aos revisores mais informações do que uma exclusão ampla sem explicação.

A nova opção --add-ignore pode inserir uma supressão automaticamente. Essa conveniência não deve substituir a revisão sobre se o diagnóstico subjacente representa um defeito real.

A automação pode rapidamente deixar o CI verde ao adicionar comentários. Ela não pode decidir se um projeto deve manter essa exceção por anos.

O Ruff separa correções consideradas seguras daquelas que exigem uma opção de correção insegura. Mesmo uma classificação como segura deve ser revisada no contexto de código gerado, APIs públicas e comportamentos incomuns em tempo de execução.

O comportamento dinâmico do Python limita o que a análise estática pode garantir. A própria orientação sobre correções do Ruff pede aos usuários que relatem casos em que uma correção segura danifica o código.

Essa limitação não enfraquece o argumento em favor do linting. Ela reforça a necessidade de distinguir detecção, modificação automatizada e aprovação humana.

Ferramentas de Desenvolvimento Sem Versão Fixada São Agora o Ponto de Pressão

A pressão imediata recai sobre repositórios que instalam o Ruff dinamicamente enquanto deixam a seleção de regras implícita.

Uma versão totalmente fixada do Ruff com uma lista select explícita tem dois controles estáveis. Um fixa a implementação da ferramenta, enquanto o outro fixa a política de lint escolhida pelo projeto.

Uma versão flutuante com regras explícitas tem estabilidade parcial. Novas versões do Ruff ainda podem alterar o comportamento de regras individuais, a análise, a saída, a formatação ou a semântica de configuração.

Uma versão fixada sem regras explícitas também tem estabilidade parcial. O CI permanece consistente até que os mantenedores atualizem o Ruff, quando a migração dos padrões chega de uma só vez.

Uma versão não fixada sem regras explícitas não tem nenhum dos dois controles. Essa combinação criou as condições por trás das falhas de CI do Ruff de Simon Willison.

Fixar uma versão não significa congelar a ferramenta indefinidamente. Isso separa a descoberta de uma atualização da sua adoção.

Um pull request de atualização de dependência cria uma fronteira de revisão visível. O CI pode mostrar as novas descobertas enquanto a branch principal existente continua reproduzível.

Os mantenedores podem então escolher entre várias respostas:

  • Corrigir defeitos claros identificados pelos novos padrões.

  • Aceitar mudanças mecânicas seguras em commits isolados.

  • Configurar exceções intencionais para padrões específicos do repositório.

  • Restaurar a seleção anterior e programar uma adoção gradual das regras.

  • Atualizar analisadores que não conseguem lidar com localizações JSON anuláveis.

  • Excluir arquivos de documentação que precisam preservar a formatação manual.

Essas ações não devem ser misturadas indiscriminadamente. Um único commit grande de autocorreção pode ocultar mudanças de comportamento entre milhares de edições de formatação.

Agrupar o trabalho por família de regras produz revisões mais claras. Também facilita a reversão caso uma regra entre em conflito com as versões de Python compatíveis com o projeto.

A configuração da versão-alvo importa quando regras do pyupgrade estão ativas. A sintaxe moderna pode estar correta para uma base de interpretador e ser inutilizável para outra.

As equipes devem verificar se a versão-alvo de Python configurada no Ruff corresponde à realidade da implantação. Caso contrário, as sugestões de modernização podem avançar além do suporte em produção.

O código gerado também exige tratamento separado. Reformatar ou aplicar lint a arquivos gerados frequentemente cria alterações que desaparecem na próxima execução do gerador.

Excluir caminhos gerados pode ser mais preciso do que preenchê-los com comentários de supressão. A fonte ou o template do gerador costuma ser o local adequado para impor qualidade.

Monorepositórios enfrentam outra complicação. Pacotes diferentes podem oferecer suporte a versões diferentes de Python ou manter políticas de lint distintas.

Um padrão no nível raiz pode simplificar as operações, mas também pode impor um único cronograma de migração a componentes não relacionados. Uma configuração por pacote pode refletir melhor a responsabilidade de cada equipe.

A principal questão cética é se 413 regras formam uma linha de base amplamente aceitável. A Astral documentou a seleção, mas a adoção no mundo real testará sua taxa de falsos positivos e seu custo de compatibilidade.

As falhas de Willison fornecem um sinal inicial, não uma pesquisa representativa. Elas mostram que a disrupção é possível, não que a maioria dos usuários do Ruff a experimentará.

Projetos que já usam um select ou extend-select explícito podem responder de forma diferente. Seu conjunto efetivo de regras depende de como essa configuração interage com a nova linha de base.

A Astral afirma que a mudança ainda pode revelar regras úteis para usuários configurados. Cada equipe deve inspecionar a seleção resolvida em vez de presumir que a configuração torna a versão irrelevante.

Também há o risco de corrigir em excesso. Fixar o Ruff enquanto se deixa todas as outras ferramentas de desenvolvimento flutuantes resolve apenas um caso visível de um problema mais amplo.

As equipes devem inventariar formatadores, verificadores de tipos, ferramentas de teste, hooks de pre-commit e geradores de documentação. Qualquer um deles pode transformar uma compilação limpa em falha.

A política duradoura é simples: versionar o ambiente que decide se o código pode ser entregue. Essa política inclui as ferramentas que os desenvolvedores tradicionalmente classificam como opcionais.

O Que Simon Willison e os Usuários do Ruff Devem Observar em Seguida

Os próximos três sinais mostrarão se a linha de base mais ampla do Ruff se tornará uma política aceita ou uma fonte recorrente de atrito no CI.

O primeiro sinal é a atividade de lançamentos de correção da Astral nas semanas posteriores à versão 0.16.0. Ajustes rápidos nas regras padrão indicariam que repositórios reais revelaram problemas significativos de compatibilidade.

Correções específicas de regras não invalidariam a linha de base expandida. Elas mostrariam que uma seleção muito maior precisa de ajustes sob cargas de trabalho de produção.

Por outro lado, uma atividade limitada de reversões fortaleceria o argumento da Astral de que a maioria dos novos diagnósticos é acionável. Isso também incentivaria mais projetos a aceitar os padrões em vez de restaurar o conjunto anterior.

O segundo sinal é o comportamento de configuração em repositórios públicos de Python. Os mantenedores revelarão sua avaliação por meio de commits, mesmo sem pesquisas formais.

Uma onda de seleções explícitas dos padrões antigos sugeriria que as equipes valorizam o controle da migração mais do que uma cobertura imediata. Correções generalizadas e padrões mantidos apontariam para uma adoção bem-sucedida.

Os repositórios mais informativos documentarão seu raciocínio. Uma simples lista de ignorados mostra o que mudou, enquanto uma nota de migração explica por que uma equipe aceitou ou rejeitou cada família de regras.

O terceiro sinal é se os templates de pacotes e exemplos de CI começarão a fixar o Ruff. Geradores de novos projetos frequentemente moldam hábitos com mais eficácia do que avisos retrospectivos.

Se os templates adotarem restrições de versão e fluxos de atualização automatizados, a experiência de Willison terá influenciado a prática além desta única versão.

Se os exemplos continuarem instalando um ruff sem restrições, futuras alterações de padrões ou do formatador poderão repetir a mesma surpresa. A contagem específica de regras será diferente, mas o problema de reprodutibilidade permanecerá.

Os desenvolvedores não precisam esperar por esses sinais antes de agir. Eles podem executar a nova versão em uma branch, preservar a saída e decidir quais descobertas melhoram seu código.

Um comando de teste útil é:

Especificar a versão torna o experimento repetível. Executar ruff format --check . separadamente ajuda a distinguir falhas de lint de alterações de Markdown ou de formatação do código-fonte.

Não comece adicionando ignorados globais. Primeiro, identifique quais regras encontraram bugs definitivos, quais sugerem modernização e quais codificam uma política discutível.

Em seguida, registre a decisão na configuração e no controle de versão. Um selo verde de CI tem menos valor quando ninguém sabe qual contrato de qualidade o produziu.

O Ruff v0.16.0 demonstra a vantagem e o custo de padrões ativos. A ferramenta detecta mais sem configuração, mas a ausência de configuração já não significa comportamento inalterado.

A experiência de Simon Willison transforma essa troca abstrata em uma questão imediata de engenharia: seu repositório declara as ferramentas e políticas que controlam suas versões?

Execute a versão fixada em uma branch, inspecione cada nova família de regras e torne a linha de base explícita. A próxima compilação limpa deve refletir uma decisão revisada, não a data em que o CI instalou o Ruff.

 
 

Comece grátis

Um assistente de IA local-first com gestão de conhecimento pessoal

Para oferecer uma experiência de IA melhor,

atualmente, o remio é compatível apenas com Windows 10+ (x64) e M-Chip Macs.

​Adicione uma barra de pesquisa ao seu cérebro

É só perguntar ao remio

Lembre-se de tudo

Não organize nada

bottom of page