# Execução — `CV-3` Encerramento antecipado pelo admin

**Plano:** `CV-3-plano.md` · **Data:** 07/08/2026
**Ambiente:** backend local (`test/ciclo-vida.e2e-spec.ts`), Flutter em teste de
widget (`test/ciclo_vida_test.dart`).

**Resultado: 9/9 ✅** — nenhum defeito; 2 casos novos (palpite depois do
encerramento e segundo encerramento recusado).

| ID | Resultado | Onde |
| -- | --------- | ---- |
| CV-3-01 | ✅ | e2e "encerramento antecipado fecha o prazo dos jogos abertos e fica marcado" |
| CV-3-02 | ✅ | e2e mesma suíte (`closedEarly: true`) |
| CV-3-03 | ✅ | e2e mesma suíte (nenhum jogo com prazo aberto) |
| CV-3-04 | ✅ **novo** | e2e "CV-3-04 depois do encerramento antecipado, palpite é recusado" |
| CV-3-05 | ✅ | e2e "participante comum não encerra nem arquiva" |
| CV-3-06 | ✅ **novo** | e2e "CV-3-06 encerrar antecipadamente duas vezes é recusado" |
| CV-3-07 | ✅ | e2e "CV-1-03 jogo adiado para depois do bolão só encerra antecipadamente" |
| CV-3-08 | ✅ | widget "encerramento antecipado exige confirmação avisando o peso" |
| CV-3-09 | ✅ | widget "encerramento antecipado é distinguido no histórico" |

## Observações

- **A assimetria entre os dois encerramentos é proposital e agora está
  testada:** o normal é **idempotente** (chamar de novo devolve o mesmo
  resultado, o que é como o app relê o campeão), o antecipado é **409** na
  segunda vez. Faz sentido: repetir o antecipado reescreveria a data e a marca do
  título. Sem os dois casos escritos, alguém "uniformizaria" isso e perderia uma
  das duas propriedades.
- **`CV-3-04` cobre a mensagem, não só o status:** a recusa tem de falar de bolão
  **encerrado**, não de prazo fechado — prazo sugere atraso do participante, e o
  participante iria discutir com o admin sobre um atraso que não existiu.
- `CV-3-01` verifica o efeito colateral que dá sentido à ação: os jogos com prazo
  aberto são fechados. Sem isso alguém palpitaria depois do encerramento e o
  ranking final mudaria sozinho.
