teqo-backup/docs/plans/simplificar-modelo-sinal.md
Francisco Ignácio Fontoura Solla 4604751b65 docs(B62): record simplify deferrals in the signal plan.
The close-delivery debt harvest defers FieldError/unify-forms and E11 query tuning to B63 and a production-volume trigger instead of opening new roadmap IDs.
2026-07-29 23:34:30 -03:00

95 lines
7.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Simplificar modelo de sinal (tipo + texto; sem fonte/triangulado)
Status: entregue em código 2026-07-29
Atualizado em: 2026-07-29
Item do roadmap: [docs/roadmap.md](../roadmap.md) (Trilha B, item B62 — UX-1 / C12 sinais)
Impeccable: B — schema + forms existentes (`MunicipalitySignalFields`, B26, admin); UI nova de escolha = **B63**
Appetite: ~0,75–1 dia eng; migration drop + zod/collection/UI lista/detail; rename de labels; ajuste E11
Responsável: —
**Revisão 2026-07-29 (as-built):** entregue conforme o plano, com duas decisões da sessão e dois achados: (1) **E11 triage 1 por presença** — o usuário decidiu que sinal de adversário registrado lê como confirmado ("eles não vão adicionar sinais improváveis"), divergindo do default "ramo fonte única" abaixo; `adversarySignal: { present: true } | null`, P1 triage 1, fator único "Sinal de adversário registrado". (2) **scrub "broker" = só o modelo de sinal** — `activity.origin` (`Pedido de broker`) e as strings "broker" do suggestionCatalog (staff-only) ficaram para o gatilho já registrado. Achados da auditoria incorporados: form duplicado em `MunicipalityUpdateForm.tsx`, readouts `municipalityUpdatePageData.ts` + `MunicipalityUpdateFeed.tsx` (detalhe + dossiê), glossário `campaignIntelligenceConcepts.ts`; migration gerada reemitia `ADD VALUE 'adiada'` (drift de snapshot da cadeia `.json` — removido à mão; o snapshot desta migration sara a cadeia). Bônus de gate: e2e `campaignMunicipalities` "advisor scopes…" obsoleto desde B43 (home liderança → `/campanha/contatos`, redirect pós-B43) atualizado; pin de bypass do `municipalityElectoralBaseline` 9→8 (drift pré-existente em main). Gate: 876 unit / 489 int / e2e alvo verde / build; Aikido 0 findings.
## Dados → decisão → apresentação
Dados: N/A neste item como superfície nova — remove campos; labels novas alimentam **B63** e B26.
## Contexto
C12 ✓ tipou `municipalityUpdate` `kind: 'sinal'` com `signalType`, `signalSource` (obrigatório) e `triangulated`. B26 ✓ e `MunicipalitySignalFields` expõem os três. Pedido de produto (2026-07-29, gate confirmado): **sinais = só tipo + texto**; dropar Fonte e Triangulado; **renomear rótulos** para militantes PT ~60 anos (sem “broker”).
E11 ✓ lê `triangulated` em sinais de adversário (`municipalityTriggers.ts` / `suggestionCatalog`) — ao dropar, o motor trata presença do sinal como o ramo “fonte única” (ou só “há sinal”), sem segunda dimensão.
## Objetivos
- Migration: remover colunas `signal_source` e `triangulated` de `municipality_update` (e enums/admin conforme snapshot Payload); `pnpm migrate:create simplify_municipality_signal_fields`.
- Zod `municipalityUpdateCreateSchema`: para `kind: 'sinal'`, exigir `signalType` + `body`; **não** exigir `signalSource`; remover `triangulated`.
- Collection `MunicipalityUpdate`: dropar fields; ajustar `beforeValidate` que hoje exige fonte.
- Labels/descriptions (enum **values** preservados — sem rewrite de rows):
| value | label | description curta |
| ------------------- | ------------------- | ----------------------------------------- |
| `invasao` | Invasão | Adversário ocupando nosso espaço |
| `esfriamento` | Rede esfriou | Aliados pararam de responder / cairam |
| `visita_adversario` | Adversário apareceu | Visita ou agenda dele no município |
| `proposta_broker` | Alguém pediu algo | Liderança/intermediário pediu ou ofereceu |
| `outro` | Outro | Fato importante que não encaixa acima |
- Atualizar `MunicipalitySignalFields`, B26 form, detail/dossier readouts, int tests, seeds se houver.
- E11: remover branch `triangulated` do input de sugestão; copy do catálogo que cita "triangulado" / "fonte única" no eixo de adversário → presença do sinal basta e **lê como confirmada (triage 1 — decisão da sessão 2026-07-29)**; recalibrar texto mínimo; **não** reabrir E15.
- Sem Consent novo. Sem UI de grid do wizard (isso é **B63**).
## Decisões travadas
- **Modelo = `signalType` + `body` apenas.** **Rejeitado:** manter fonte/triangulado opcionais “por se acaso” (pedido: simplificar; campos mortos confundem mesa).
- **Enum values estáveis; só labels/descriptions mudam.** **Rejeitado:** renomear `proposta_broker` → `proposta_intermediario` neste slice (migration de dados + grep em E11/tests sem ganho de UX). Gatilho: se copy interna/código ainda vazar “broker” em string de usuário após labels — aí rename.
- **E11 sem dimensão triangulado.** **Rejeitado:** inventar proxy (“texto longo = triangulado”); manter coluna só para o motor.
- **i18n:** ids `invasao`…; copy pt-BR nova.
## Questões em aberto
- **Textos longos do drawer de info (B63) — quem redige?** **Opções:** A eng com copy provisória no plano B63 | B assessoria. **Recomendação:** A no ship (o quê / consequências / quando usar em 3–5 frases); B revisa no R6. _(assumido)_
## Abordagem proposta
```mermaid
flowchart LR
Mig["migration DROP fonte/triangulated"] --> Zod["zod + collection"]
Zod --> UI["SignalFields + B26"]
Zod --> E11["triggers/catalog"]
```
Componentes:
- Migration + `MunicipalityUpdate.ts` + `municipalityUpdate.ts` schema.
- `MunicipalitySignalFields.tsx` — select de tipo + textarea; sem checkbox/fonte.
- `municipalityTriggers.ts` / `suggestionCatalog.ts` — dropar `triangulated` do tipo de input.
- View models de update/dossier — parar de exibir fonte/triangulado.
- **Migration:** sim (drop columns; sem backfill necessário além de drop).
## Dependências
- Dura: **C12** ✓. Soft: B26 ✓ (superfície a atualizar). Desbloqueia **B63**.
## Não escopo
- Grid de botões + drawer de info + “Pular” → **B63**.
- Novos tipos de sinal (Perda de apoio / Novo apoio do rascunho UX-1) — **não** expandir taxonomia neste item; só renomear os 5 existentes. Gatilho: sessão pedir tipo que não cabe em `outro`.
## Rabbit holes
- **Reescrever taxonomia inteira + migração de valores históricos.** **Mitigação:** labels only.
- **Unificar `kind` urgente/nota com sinal.** **Mitigação:** fora — C12 já separou.
## Adiado com gatilho
- **Rename enum `proposta_broker`.** Revisitar se `broker` ainda aparecer em UI/admin após labels (grep pt-BR + admin).
- **Novos signalType values.** Revisitar com evidência de mesa (tipos que caem sempre em `outro`).
- **`FieldError` de `signalType` no detalhe (`MunicipalityUpdateForm`).** Gap pré-existente: o form inline não renderiza erro de servidor no select de tipo (a lista B26 já usa `MunicipalitySignalFields` com `FieldError`). **Gatilho:** **B63** (wizard + unificação dos dois forms de sinal).
- **Unificar `MunicipalitySignalFields` + bloco inline do detalhe.** Duplicação aceitável pós-B62 (só tipo + textarea); **gatilho:** **B63** (3º call site do wizard).
- **Consulta de existência de sinais no loader E11.** Hoje `limit: 0` na janela de 28d é barato; se o volume crescer, trocar por agregado/exists — **gatilho:** fila de sugestões lenta ou >N sinais/dia por município em produção.
## Referências
- [registro-fundacao.md](registro-fundacao.md) · [registrar-sinal-lista-municipios.md](registrar-sinal-lista-municipios.md) · [motor-de-sugestoes.md](motor-de-sugestoes.md) · `src/lib/schemas/municipalityUpdate.ts` · `src/collections/MunicipalityUpdate.ts` · `MunicipalitySignalFields.tsx` · `municipalityTriggers.ts`
- AGENTS.md — migrations; `overrideAccess: false`
- Impeccable: B — craft compacto nos forms existentes