A dívida
As mutações comportamentais — as que provam que um caso de eval morde — são feitas à mão, em cópias descartáveis, com perl -0pi -e e sem nenhuma verificação de que a edição aconteceu.
O mutation_test.sh não tem esse problema: ele guarda cksum de MUTATED_FILES antes e depois e reporta STALE quando uma mutação não muda nada — guarda que existe desde a #37 exatamente porque uma mutação que não aplica reporta "a suíte pegou" para sempre, e o vermelho que ela deveria produzir nunca aparece.
Fora dali, nada protege. E o custo é assimétrico: mutação comportamental é a cara — minutos e cota de modelo por execução — e é a que produz as conclusões mais fortes do repositório ("o contrato do RED só cai quando as quatro sedes caem", "o teto de fase não morde neste fixture").
Não é hipótese: aconteceu hoje
Ao escrever o invariante da #85, a primeira mutação de verificação foi STALE. O perl não casou, o arquivo não mudou, e a suíte respondeu 465/465 invariants held — que eu quase li como "o invariante não morde".
Só apareceu porque conferi o cksum antes de acreditar no resultado. A leitura errada estava a um passo: "o invariante que acabei de escrever não reprova, então preciso reescrevê-lo" — e o invariante estava certo.
O mesmo risco vale na direção oposta e é pior: uma mutação STALE num caso de eval faria a run legítima rodar contra o texto original, e o verde resultante leria como "o caso não morde", quando o que houve foi uma edição que nunca existiu. Custo: uma run paga e uma conclusão invertida.
Escala do que está desprotegido
Só no lote do milestone anterior: doze mutações ad-hoc na #69, duas na #66 (célula única e conjunto das quatro sedes), uma na #67, uma na #65, mais as de verificação de invariante. Nenhuma com guarda. Que elas tenham aplicado foi verificado por hábito, lendo o trecho mutado de volta — não por mecanismo.
O que resolve
Um utilitário pequeno, na linha do que o mutation_test.sh já faz: aplica a edição, compara o checksum, aborta se não mudou. Três exigências que decidem se ele é útil ou decorativo:
- Aborta, não avisa. Guarda que imprime aviso e segue é guarda que some no scroll de uma run de quatro minutos.
- Serve para as duas metades. Mutação de texto (barata, para invariante) e mutação de comportamento (cara, para eval) têm o mesmo modo de falha silenciosa, e a distinção entre elas é o assunto da #80.
- Reporta o que mudou, não só que mudou. Uma regex gulosa que come metade do arquivo também muda o checksum, e o vermelho que ela produz não é o vermelho que se queria.
Critério de pronto
A dívida
As mutações comportamentais — as que provam que um caso de eval morde — são feitas à mão, em cópias descartáveis, com
perl -0pi -ee sem nenhuma verificação de que a edição aconteceu.O
mutation_test.shnão tem esse problema: ele guardacksumdeMUTATED_FILESantes e depois e reportaSTALEquando uma mutação não muda nada — guarda que existe desde a #37 exatamente porque uma mutação que não aplica reporta "a suíte pegou" para sempre, e o vermelho que ela deveria produzir nunca aparece.Fora dali, nada protege. E o custo é assimétrico: mutação comportamental é a cara — minutos e cota de modelo por execução — e é a que produz as conclusões mais fortes do repositório ("o contrato do RED só cai quando as quatro sedes caem", "o teto de fase não morde neste fixture").
Não é hipótese: aconteceu hoje
Ao escrever o invariante da #85, a primeira mutação de verificação foi
STALE. Operlnão casou, o arquivo não mudou, e a suíte respondeu465/465 invariants held— que eu quase li como "o invariante não morde".Só apareceu porque conferi o
cksumantes de acreditar no resultado. A leitura errada estava a um passo: "o invariante que acabei de escrever não reprova, então preciso reescrevê-lo" — e o invariante estava certo.O mesmo risco vale na direção oposta e é pior: uma mutação
STALEnum caso de eval faria a run legítima rodar contra o texto original, e o verde resultante leria como "o caso não morde", quando o que houve foi uma edição que nunca existiu. Custo: uma run paga e uma conclusão invertida.Escala do que está desprotegido
Só no lote do milestone anterior: doze mutações ad-hoc na #69, duas na #66 (célula única e conjunto das quatro sedes), uma na #67, uma na #65, mais as de verificação de invariante. Nenhuma com guarda. Que elas tenham aplicado foi verificado por hábito, lendo o trecho mutado de volta — não por mecanismo.
O que resolve
Um utilitário pequeno, na linha do que o
mutation_test.shjá faz: aplica a edição, compara o checksum, aborta se não mudou. Três exigências que decidem se ele é útil ou decorativo:Critério de pronto
mutation_test.sh