Blogue ·
Um script de conversão que abrangeu demasiado
Um script de tipografia curvou um apóstrofo numa citação de saída de programa, num artigo em que nunca devia ter tocado. Tudo continuou verde.
Por Provibr
O francês e o italiano exigem um apóstrofo tipográfico em vez de um reto, e há um teste que o impõe. Escrever esse carácter diretamente num ficheiro de origem não é fiável: consoante a maneira como o ficheiro é produzido, uma linha de comandos, um heredoc ou uma ferramenta de edição podem achatá-lo outra vez. Por isso escrevemos o carácter reto e corremos a seguir um pequeno script que o converte.
Esse script mascara o código. Tudo o que esteja entre acentos graves e tudo o que esteja dentro de um bloco delimitado fica intocado, porque um apóstrofo dentro de um fragmento de código alteraria o fragmento, e a comparação de factos ficaria vermelha, com toda a razão.
Foi corrido como um glob sobre uma pasta de língua inteira. Converteu um apóstrofo dentro de uma citação de saída de programa, num artigo escrito por outra ronda, que por acaso estava na mesma pasta.
O mascaramento estava certo e o alvo estava errado
A linha que danificou era uma citação daquilo que um comando imprimiu, colocada entre aspas angulares como prosa corrida e não marcada como código. Algo com a forma Locking administration user's password. Esse apóstrofo pertence à máquina que o emitiu, e curvá-lo faz o artigo afirmar que a máquina disse algo que não disse.
A regra de mascaramento está certa. Os acentos graves e os blocos delimitados são código. Uma citação de saída de programa composta como prosa não está marcada como código e não pode ser distinguida de prosa olhando para os caracteres, porque é precisamente isso que ela é: prosa, a citar uma máquina.
Portanto o defeito não está no mascaramento. Está na seleção. Três artigos de outras rondas foram modificados por um script que foi escrito para tocar em quatro.
Porque é que a verificação de compilação não deu por isso
Esta é a parte que se generaliza para além de um script.
Os nossos artigos são gerados. A fonte é markdown, a saída são ficheiros gerados que ficam no repositório, e há uma verificação que reconstrói a partir da fonte e exige que o resultado seja idêntico byte a byte ao que está no repositório. Se divergirem, fica vermelha.
Não divergiram. O script alterou a fonte, a compilação correu, a saída foi regenerada a partir da fonte alterada, e as duas coincidiram na perfeição. A verificação responde a «a saída é coerente com a fonte», que é uma pergunta a sério e não é esta. Nada na cadeia responde a «esta ronda alterou apenas aquilo que devia alterar».
O teste de tipografia também não, pela mesma razão ao contrário: um apóstrofo curvo em francês é o carácter correto. A alteração tornou o ficheiro mais conforme, não menos.
A única coisa que o revelou foi o git status sobre caminhos fora dos ficheiros da própria ronda. Passa a ser essa a regra: depois de correr qualquer transformação, liste os ficheiros alterados e confirme que todos são seus.
A regra que daí decorre
Corra um script de transformação sobre os nomes dos ficheiros da sua própria ronda. Nunca sobre um glob de uma pasta.
Escrito assim parece óbvio, e não era óbvio enquanto se escrevia, porque um glob sobre uma pasta de língua é a maneira natural de exprimir «converter os artigos franceses» e o script tinha uma propriedade de segurança correta que o fazia parecer seguro: exige pelo menos uma substituição por ficheiro, para que uma execução que em silêncio não faça nada não possa comunicar sucesso. Essa verificação é sobre o sucesso vazio. Não diz nada sobre o âmbito.
Uma verificação de segurança que protege contra fazer de menos não é uma verificação de segurança contra fazer de mais. São propriedades separadas e precisam de mecanismos separados.
Duas versões mais pequenas do mesmo problema
A ronda que esbarrou nisto esbarrou também em duas falhas de tradução vindas da mesma família: algo que devia ter estado imune à edição não estava marcado como tal.
Uma diretiva de cache aparecia na fonte como prosa nua em vez de estar entre acentos graves. Duas línguas traduziram-na, o que transforma uma palavra-chave numa expressão, e uma delas transformou ainda uma duração de um ano num plural. Nenhuma das duas é apanhada pela comparação de factos, porque essa comparação cobre o que está entre acentos graves e o que é um algarismo, e uma palavra-chave nua não é nem uma coisa nem outra. A reparação é marcá-la como símbolo nas nove línguas, e a partir daí a comparação cobre-a para sempre.
A segunda era uma tabela de rótulos de interface. O artigo inglês usava-a para mostrar que duas listas de nomes se tinham afastado uma da outra, e declarava explicitamente que o afastamento tinha sido medido em inglês. Seis das oito traduções traduziram a tabela. Um par de nomes traduzido não é uma versão mais suave da medição; é uma medição diferente, que nunca foi feita. Desfazer isso levou 26 substituições.
Ambas as falhas têm a mesma forma do apóstrofo: um pedaço de texto que é dados e não linguagem, colocado numa posição em que nada o marca como dados.
Aquilo a que uma verificação responde é mais estreito do que parece
Os três mecanismos aqui em jogo estão cada um correto e cada um respondeu a uma pergunta vizinha daquela que interessava.
| Verificação | A pergunta a que responde | A pergunta a que não responde |
|---|---|---|
| A verificação de compilação do conteúdo | a saída gerada é coerente com a fonte | esta alteração tocou apenas em ficheiros pretendidos |
| O teste de tipografia | este ficheiro usa os caracteres certos para a sua língua | esses caracteres estão nos sítios certos |
| A guarda do próprio script | este ficheiro recebeu pelo menos uma substituição | algum ficheiro recebeu uma substituição que não devia |
Nenhum destes está mal desenhado. A falha é o pressuposto de que uma parede de verificações verdes constitui cobertura, quando aquilo que constitui de facto é cobertura das coisas em que alguém pensou.
A defesa mais barata contra isso não é mais uma verificação. É olhar para a diferença, ao nível dos nomes dos ficheiros, antes de submeter o que quer que um script tenha produzido.
O que registaríamos
- Delimite uma transformação aos ficheiros da sua própria ronda. Um glob sobre uma pasta não é um âmbito, é uma categoria.
- Uma guarda contra fazer de menos não diz nada sobre fazer de mais. São propriedades diferentes.
- Uma citação de saída de programa é dados. Marque-a como código, ou uma transformação de texto tratá-la-á como linguagem.
- Uma verificação de coerência entre a fonte e a saída é cega a uma alteração em ambas. Responde sobre concordância, não sobre intenção.
- Uma alteração que torna um ficheiro mais correto é a mais difícil de notar, porque todos os sinais de qualidade apontam no sentido certo.
- Leia a lista de ficheiros da sua própria diferença. É a única verificação que responde à pergunta do âmbito.
- Tudo o que seja uma palavra-chave pertence entre acentos graves na fonte, em todas as línguas, ou alguém a traduzirá e nenhum teste se importará.
- Uma medição traduzida é uma medição inventada. Se o objetivo de uma tabela é que duas coisas diferem, a tabela é prova e não prosa.
Para que fique claro o que isto é: o dano foi revertido, a ronda terminou com a verificação de conteúdo em 815 de 815 ficheiros gerados idênticos byte a byte, a bateria de testes da web em 4546 verdes, as baterias dos pacotes, do gateway e das ferramentas em 7236 verdes, a comparação de factos sobre 1240 parágrafos sem achados, as ligações em 81 de 81, as tabelas em 99 de 99 e a varredura de disposição em 108 de 108 a 390 píxeis contra uma compilação de produção. O teste de tipografia foi provado vermelho com dois defeitos plantados e verde depois disso. Por provar: há um leitor por tradução, três línguas foram verificadas apenas quanto a disposição, tipografia e estado de HTTP, e os números citados de rondas anteriores não foram medidos de novo aqui.
Do trabalho de plataforma na Provibr. O que um segundo leitor encontrou nos mesmos oito artigos está em três falhas que nenhum script conseguia ver, e o que nove catálogos fazem a um conjunto fixo de controlos está em dezasseis mil chaves, nove idiomas.