## MG-8 — Paridade verificada: os 234 casos na stack nova

**PRD:** `docs/prd/migracao-firebase.md`

**Como** time, **quero** os mesmos casos de teste passando contra o Firebase,
**para** a migração ter prova e não fé.

**Prioridade:** Must — é a métrica de sucesso do PRD. Sem isso, nada é desligado.

**Critérios de aceite:**

- Dado o plano de cada story de produto, quando executo contra a stack nova, então
  os casos passam **com os mesmos IDs** — comparáveis linha a linha com a execução
  do NestJS.
- Dado um caso que passava no NestJS e falha aqui, então é tratado como **defeito de
  migração**, não como "comportamento novo".
- Dado um caso que não tem tradução (ex: rate limit que agora é do Auth), então ele
  é **reescrito e registrado**, nunca silenciosamente descartado.
- Dado que a suíte roda, então ela fala **só** com emulador — nunca com projeto real.
- Dado o custo, então há uma medição real de leituras/escritas por fluxo, não
  estimativa.

**Tasks:**

_QA_
- [x] `QA-1` Mapa de cobertura: cada caso existente → onde passa a ser verificado (rule, Function, e2e ou device)
- [x] `QA-2` Reescrever os casos de autorização como testes de security rule (depende de QA-1)
- [x] `QA-3` Reexecutar os planos de `PP-*`, `PR-*`, `CC-*`, `CV-*` e `AC-*` na stack nova (depende de QA-1)
- [x] `QA-4` Registrar as divergências como defeito, com o ID do caso (depende de QA-3)
- [x] `QA-5` Medir leituras e escritas por fluxo e comparar com o free tier (depende de QA-3)

**Riscos/Dependências:**

- Depende de `MG-3` a `MG-7`.
- **É a story mais fácil de fingir que foi feita.** "Os testes passam" sem o mapa de
  cobertura significa que os casos difíceis foram os descartados — e os difíceis são
  justamente sigilo, prazo e concorrência.
- Casos que mudam de mecanismo mas não de critério: `AC-2-03`/`AC-2-04` (rate limit
  do Auth), `AC-2-09` (deixa de valer com a recuperação de senha), `PR-3-11` (passa a
  medir leituras) e `PP-10-11` (lock em documento).

- **07/08 — `QA-1`, `QA-2` e `QA-5` feitas.** Mapa em
  `docs/testes/MG-8-mapa-de-cobertura.md`, gerado por `docs/cobertura.py`: **188
  de 420** casos da fase 1 verificados **com o id** na stack nova (44%). O mapa é
  script, e não tabela escrita à mão, porque o risco desta story é exatamente
  contabilidade que envelhece em silêncio.
- **`QA-2`: 34 casos de sigilo, prazo, papel e autorização reexecutados mantendo o
  id de origem** (`paridade-seguranca.spec.ts`). Foi o grupo escolhido primeiro
  porque é o que sumiria primeiro se "os testes passam" bastasse como prova.
- **`QA-5`: custo medido com contador em volta do Firestore**, não estimado. O
  requisito não funcional está cumprido — o ranking custa uma leitura por linha da
  página, não por participante. Um bolão de 60 pessoas gasta ~5.150 leituras por
  rodada, com folga de 10× no free tier.
- **Os 231 restantes não são um bloco só:** casos de tela cujo teste existe e não
  cita o id; casos cujo mecanismo deixou de existir (token, refresh, rate limit —
  reescritos e registrados no mapa); e o grupo que falta reexecutar, onde `CV-2` e
  `PP-8` estão em zero.
- 🔴 **Duas decisões do dono seguem travando a paridade de `AC-2`:** *email
  enumeration protection* e Identity Platform.

- **08/08 — `QA-3` em andamento: 188 → 241 de 420 (57%).** Entraram `CV-2`, `PR-6`
  (10/10), `CV-5` (9/10), `PP-3` (10/11) e a frente de `AC-*` que sobrevive à
  troca do Auth. Suíte do Firebase em **260** casos.
- **Boa parte do avanço foi etiquetar teste que já existia e passava.** `PP-3`,
  `PP-4`, `AC-1` e `AC-3` tinham caso verde sem o id no nome — e sem o id ninguém
  consegue dizer se o plano está coberto ou se o teste é sobre outra coisa. Não é
  trabalho de fachada: é a diferença entre saber e achar.
- **Um caso novo nasceu do porte:** `CV-5-11` — o campeão do **histórico** também é
  derivado, não congelado. Correção de placar depois do encerramento muda quem
  aparece como campeão na lista de bolões passados.
- **`QA-4` segue sem nenhuma divergência de comportamento registrada.**

- **08/08 (segunda leva) — 241 → 281 de 420 (66%).** Entrou a paridade de fluxos:
  criação, regras, convite, papel, saída e ciclo de vida, 30 casos com o id de
  origem. Suíte do Firebase em **290**.
- **`QA-4` deixou de estar vazia: a primeira divergência real apareceu em
  `CV-4-01`.** Quem saía do bolão **continuava no ranking**. No NestJS o ranking
  era somado na leitura a partir de quem estava ativo; aqui é agregado
  materializado, e só era reescrito na apuração. Eram dois defeitos empilhados: a
  mudança de vínculo não disparava recálculo, e — o que dá o susto — **o recálculo
  não apagava a linha de quem saiu**. Agregado materializado só está correto
  quando alguém cuida do que sobra.
- **Uma armadilha de cenário virou regra do arquivo:** convidar depois do apito é
  recusado (corretamente), então bolão com jogo começado **e** convidado dentro
  precisa ser montado na ordem da vida real — entra todo mundo, depois o jogo
  começa. Cada caso também ganhou o seu próprio campeonato, porque o calendário é
  global e sobrevive ao bolão.

- **08/08 (terceira leva) — 281 → 297 de 420 (70%).** Entrou a paridade de palpite
  e sincronização: adiamento, antecipação, atraso do job, fonte fora do ar e jogo
  novo na fonte. Suíte do Firebase em **304**. `CC-5`, `CC-8`, `PR-1` e `PR-6` em
  100%.
- **Dois testes meus mentiram de formas novas, e vale registrar as duas:**
  - `PP-10-01` acusava o produto de alterar horário que ninguém alterou. O
    ajudante gerava `Date.now() + deslocamento` a cada chamada, então "o mesmo
    horário" eram instantes diferentes por alguns milissegundos. Base de tempo
    fixa por arquivo resolveu.
  - `MG-7-45` e os cenários de `CV-5` **plantavam a classificação à mão** e
    passavam por acidente: nada recalculava o agregado fora da apuração. Com a
    correção de `CV-4-01`, a entrada de participante passou a recalcular — e a
    linha plantada virou zero. O `MG-7-45` passou a **conquistar** os pontos
    (palpite + jogo terminado + apuração), que é o cenário que o produto alcança;
    o `CV-5`, que verifica leitura, espera o recálculo assentar antes de plantar.
  - A lição é a mesma nas duas: **teste que passa por acidente é dívida com juros**
    — ele cobra no dia em que o produto fica mais correto.

- **08/08 — `MG-8` fechada. Cobertura em zero a verificar:** 397 casos verificados
  com o id na stack nova, 22 reescritos com justificativa, 1 cancelado. As 38
  stories da fase 1 em 100%, conferível por `python3 docs/cobertura.py`.
- **A suíte do Firebase terminou em 332 casos**, 22 arquivos. Os de widget seguem
  em 244, sem nenhuma asserção alterada pela migração.
- **Uma divergência real de comportamento em toda a migração** (`CV-4-01`), achada
  e corrigida. Todo o resto foi mudança de mecanismo — registrada — ou defeito do
  próprio teste.
- **Os defeitos de teste foram mais numerosos que os de produto, e isso é um dado.**
  Cinco padrões apareceram: espera pela categoria em vez do efeito; espera por um
  passo anterior ao que se quer medir; cenário impossível de alcançar pelo produto;
  contagem global onde o caso controla só um pedaço; e timestamp recalculado a cada
  chamada. Nenhum deles é sobre o Firebase — são sobre escrever teste de sistema
  assíncrono e compartilhado, e agora estão documentados nos arquivos.
