# Prova: Guard Cego

> Escopo: Gate 3 (avaliador independente). Não é dimensão do score composto — impõe **teto** em
> Cobertura de Testes (`evals/rubrics/test-coverage.md`, seção "Tetos de prova").

## O que esta prova responde

Um guard só vale contra o ataque que ele consegue VER. O jeito de descobrir o que ele não vê não é
mudar o conteúdo que ele já inspeciona — é mudar a **FORMA** do que chega até ele.

A pergunta é: **qual entrada válida este guard deixa passar sem enxergar, e o ramo que ele abriu
tem teste próprio?**

## Bandas 0-10

| 0-3 | 4-6 | 7-8 | 9-10 |
|---|---|---|---|
| Guard sem teste próprio. Ou testado só com o conteúdo que ele já rejeita, nunca com forma diferente | Ataque por conteúdo apenas. Guard que compara `Serialize(A) == Serialize(B)` aceito sem cross-check | Ataque por forma feito; falta o cross-check por contador independente, ou o predicado do guard continua mais estreito que a ação que ele governa | Forma atacada (multi-linha, aninhamento, ordem, codificação), cross-check por contador independente, predicado tão largo quanto a ação, e todo ramo recém-alcançável com teste próprio |

## Anti-padrões literais

- **Atacar o guard só pelo conteúdo** — mude a **FORMA**. Medido: o guard era um parser linha a
  linha e o YAML **multi-linha** era perfeitamente válido; o conteúdo proibido passou inteiro
  porque chegou numa forma que o parser não montava.
- **`Serialize(A) == Serialize(B)` como prova de igualdade** — o guard é cego ao próprio
  serializador: se ele perde um campo, perde nos dois lados e a comparação dá igual. Faça
  **cross-check por um contador independente** (número de itens, soma, hash de um campo-chave).
- **Predicado mais estreito que a ação que ele governa** — um publish que só olhava o *spec* e
  virava no-op sobre tudo o mais. Afirme sobre o **texto publicado**, não sobre a intenção de
  publicar.
- **Early-return depois do filtro** — o `return` sai antes da limpeza e o estado fica meio mutado.
  Quando o filtro é um `skip`, transforme-o em `else`: o caminho de saída precisa passar pelo
  mesmo fecho.
- **Ramo antes inalcançável que passou a ser alcançável** — isso é **código NOVO**, ainda que a
  linha seja antiga e o diff não a toque. Ele precisa de teste próprio; nenhuma cobertura anterior
  responde por ele.
- **Guard novo sem prova de que morde** — canário que não morde é canário errado, e canário que
  morde pelo motivo errado é pior: mute a produção, exija que o teste FALHE **nomeando o que
  quebrou**, e restaure por cópia de bytes feita antes.

## Como registrar no relatório

Uma linha por guard tocado, dizendo a forma atacada e o resultado:

```markdown
- `chain.js:blockRawWorktreeAdd` — atacado por FORMA: comando com `\` de continuação em duas linhas
  e com aspas simples. Bloqueou nas duas. Cross-check: contador de comandos bloqueados subiu 2.
- Ramo `options.discardIgnored === true` era inalcançável antes de T4 — agora é alcançável e ganhou
  teste próprio (`finish.test.js:412`).
```

E no `**Proof-Scores:**`, a chave `guard`.
