teqo/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

7.5 KiB
Raw Blame History

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 (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

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