diff --git a/docs/plans/desbloquear-deploy-decisao-demanda.md b/docs/plans/desbloquear-deploy-decisao-demanda.md new file mode 100644 index 00000000..3fe53508 --- /dev/null +++ b/docs/plans/desbloquear-deploy-decisao-demanda.md @@ -0,0 +1,80 @@ +# Desbloquear deploy: decisão de demanda em /campanha parou de gravar (regressão pós-react-audit) + +Status: rascunho +Atualizado em: 2026-08-25 +Issue: #921 +Priority: P1 +Impeccable: A — N/A (sem UI) +Rascunho UI: N/A — sem UI +Appetite: ~0,5–1 dia eng; um outcome verificável (decisão de demanda gravando + deploy verde) +Responsável: — + +## Intenção + +3 deploys manuais seguidos falharam em 2026-08-25 — o último verde foi 9c5cd783 (2026-08-24). O motivo não é infra: é um **bug de produto real** que o e2e full do deploy pegou. Desde o react-audit (família 4), o assessor/coordenador que abre uma demanda, escreve a nota e clica em Aprovar/Rejeitar não consegue decidir nada: a ação cai em erro de validação, os botões continuam na tela e a decisão nunca grava. Nenhuma decisão de produto está em jogo — o comportamento correto já existia e precisa voltar, sem desfazer o ganho do C139 (nota digitada preservada em erro de validação). + +## Persona e fluxo + +- **Persona / contexto:** assessor e coordenador de campanha, na mesa, triando as demandas que chegam dos municípios no `/campanha`. +- **Job principal:** decidir uma demanda — aprovar ou rejeitar, com nota registrada. +- **Fluxo desejado:** abre a demanda → escreve a nota → clica em Aprovar (ou Rejeitar) → a transição grava, os botões de decisão somem e a tela mostra "Esta demanda já foi decidida.". +- **Anti-goals de produto:** (1) não desfazer o C139 — a nota digitada não pode sumir em erro de validação; (2) não reduzir cobertura e2e (nada de skip, remoção ou rebaixamento do teste); (3) não entrar na família de flakes #882 — é outro trabalho, já rastreado. + +## Objetivo e aceite + +1. Decidir demanda volta a gravar: com nota preenchida, Aprovar/Rejeitar conclui a transição e a tela passa a exibir "Esta demanda já foi decidida.". +2. O teste determinístico volta a passar: `tests/e2e/campaignMunicipalities.e2e.spec.ts:764` ("advisor opens a demand and decides it") verde em execução local e no verify do deploy. +3. **Critério final da Issue:** um deploy manual a partir de main termina com job `verify` verde **e** job `deploy` concluído — app novo no ar (jorgesolla1313.com.br). + +Guardrails de produto: o comportamento do C139 vale para todos os formulários do padrão; nenhum outro formulário muda nesta entrega; nada de tocar retries/workers da suíte. + +## Dados (intenção) + +N/A — sem decisão de dado. É correção de regressão: o "dado" do aceite é o comportamento do fluxo e o resultado do workflow (verify verde + deploy concluído), não uma superfície nova de informação. + +## Dados da decisão (literais) + +- **Runs falhas de 2026-08-25:** https://github.com/fsolla/teqo/actions/runs/32896463144 (main 618e37ee — verify falhou no E2E full), https://github.com/fsolla/teqo/actions/runs/32864831565 (verify verde 195 passed/10 flaky; deploy falhou: "The job was not acquired by Runner of type self-hosted"), https://github.com/fsolla/teqo/actions/runs/32870455856 (verify verde 197 passed/8 flaky; deploy cancelado). +- **Último deploy verde:** 9c5cd783 (2026-08-24). +- **Teste determinístico:** `tests/e2e/campaignMunicipalities.e2e.spec.ts:764` "advisor opens a demand and decides it", asserção na linha 817: `expect(page.getByText('Esta demanda já foi decidida.')).toBeVisible()` — falhou 3× (inicial + 2 retries), 10s timeout. As outras 6 falhas da run foram flaky e passaram no retry (família #882, fora de escopo). +- **Commit causador:** e273e9ec (react-audit família 4, C139 leftover "dispatch manual preserva texto digitado em erro de validação") trocou `action={submitTransition}` por `onSubmit` manual em `src/components/campaign/demand/DemandWorkflowCard.tsx`. O handler (linhas 70-73) monta `new FormData(event.currentTarget)`, que **não** inclui o botão submetido; os botões de transição têm `name="status" value={target}` (linhas 131-135: `em_analise` | `escalada` | `aprovada` | `rejeitada`). A server action `transitionDemandFormAction` (`src/app/(campaign)/campanha/(app)/demandas/[slug]/formActions.ts:45`) lê `requiredFormText(formData, 'status')` → ausente → erro de validação → transição nunca grava. +- **Comando repro (worktree provisionado):** `pnpm test:e2e --no-deps -- tests/e2e/campaignMunicipalities.e2e.spec.ts -g "advisor opens a demand and decides it"` (`--workers=1` se colidir no seedTestUser; `E2E_PROD=1` espelha o verify). +- **Cobertura do CI (por isso o e2e é obrigatório antes do push, política OPS72):** o PR CI **não** roda esse spec — `src/components/campaign/demand` cai na entrada final do manifest (`scripts/lib/e2e-affected-manifest.mjs:246-281`) → smoke fallback `campaignHomeActions`; o spec só roda no full do deploy verify. O aceite final é o deploy. +- **Fatos verificados:** único formulário do padrão com botões nomeados é o DemandWorkflowCard (verificado nos ~20 arquivos com `startTransition`+`new FormData`); TS 6.0.3 lib.dom aceita `new FormData(form, submitter)` (2º arg `HTMLElement | null`); React 19.2.4; zero usos atuais de `.submitter` no repo; sem cobertura unit/int do glue FormData→registro (`tests/int/campaignDemandWorkflow.int.spec.ts` cobre só a camada de registro). +- **Runner:** conferir que o runner self-hosted do homeserver está online antes de disparar o deploy (falha "job was not acquired" é de disponibilidade, não deste item). +- **Precedente de aceite:** `docs/plans/desbloquear-deploy-e2e-verify.md` (OPS83, #824). +- **ID reservado:** E2E-DEMAND-DECIDE (registrar via `pnpm agent:register` ao criar a Issue). + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** `src/components/campaign/demand/DemandWorkflowCard.tsx` (handler de submit das transições) e `src/app/(campaign)/campanha/(app)/demandas/[slug]/formActions.ts` (server action que lê `status`). +- **Precedente a olhar:** `docs/plans/desbloquear-deploy-e2e-verify.md` (OPS83, #824) — mesmo formato de critério: deploy manual verde como aceite final. +- **Risco de acoplamento:** manter o dispatch manual do C139 em **todos** os outros formulários (só o DemandWorkflowCard tem botões nomeados); não reverter a família 4 inteira. + +## Dependências + +Nenhuma dura. Referência soft: #882 (família de flakes) — citada como contexto, não como dependência nem alvo. + +## Fora de escopo + +- Família de flakes da #882 (as 6 falhas que passaram no retry). +- Corrigir a cobertura do manifest de e2e afetados (`e2e-affected-manifest.mjs`) — item sucessor sugerido, não neste. +- Consertar a infra do runner self-hosted do homeserver — checar que está online é parte do critério; consertar o homeserver não é. + +## Rabbit holes de produto + +- **Reverter toda a família 4 do react-audit.** Se alguém "só completar" revertendo o commit, o C139 (nota preservada em erro de validação) some junto. **Corte neste item:** correção local no card de demanda. +- **Converter todos os formulários do padrão para outra abordagem.** Explosão de escopo em ~20 arquivos sem benefício agora. **Corte neste item:** um único formulário — o único com botões nomeados. +- **Caçar os flakes da #882 nesta entrega.** Trabalho paralelo com rastreio próprio. **Corte neste item:** foco no teste determinístico; flakes são só ruído a ignorar. + +## Questões em aberto (produto) + +- **(a) Incluir o submitter também no formulário de custo (`handleCostSubmit`) por uniformidade?** **Opções:** incluir agora | deixar como está. **Recomendação:** incluir — é barato e previne a mesma classe de bug no futuro, mesmo sem botão nomeado hoje. +- **(b) Adicionar teste unit do glue FormData→status?** **Opções:** exigir agora | decidir no impl (opcional) | não. **Recomendação:** deixar para o plano de implementação decidir — desejável, mas não bloqueia o deploy; o aceite real é o e2e no verify. + +## Referências + +- ID reservado: **E2E-DEMAND-DECIDE** (ainda não registrado). +- Runs: https://github.com/fsolla/teqo/actions/runs/32896463144 · …/32864831565 · …/32870455856; último deploy verde 9c5cd783. +- Precedente: `docs/plans/desbloquear-deploy-e2e-verify.md` (OPS83, #824). +- Arquivos: `src/components/campaign/demand/DemandWorkflowCard.tsx`, `src/app/(campaign)/campanha/(app)/demandas/[slug]/formActions.ts`, `tests/e2e/campaignMunicipalities.e2e.spec.ts`, `tests/int/campaignDemandWorkflow.int.spec.ts`, `scripts/lib/e2e-affected-manifest.mjs`.