* docs(A6): freshness audit da #27 no plano de dobradinhas 2026 electionInsights.ts foi deletado no Pass 2 W4a (modulo puro novo), electionAlliances.ts nao nasce (campoParties + electionPartySpectrum ja carregam a taxonomia), questoes em aberto resolvidas (tiers, score, proporcionais, lockdown de lideranca), card na aba Eleicoes, overview da lista fora de escopo, cache election-tse com bust na conciliacao Fase 5. Co-authored-by: Francisco Solla <fsolla@users.noreply.github.com> * feat(A6): insight de dobradinhas 2026 na aba Eleicoes do municipio Lista ranqueada de candidatos proporcionais que concorrem de novo em 2026 (runningAgain2026=sim) por geografia do municipio: score 0,6 alinhamento (campo 2026 + espectro Bolognesi) + 0,4 forca local normalizada pelo maximo do conjunto. Estado pendente ate a conciliacao pos-15/08; Solla excluido (referencia, nao parceiro); leitura derivada sem escrita; loader cacheado sob a tag election-tse como os irmaos; link para /campanha/dobradinhas como caminho de registro operacional. Co-authored-by: Francisco Solla <fsolla@users.noreply.github.com> * test(A6): cobertura unit/int do insight + lease das colecoes eleitorais Unit: tiers (campo/espectro/falha-para-o-meio), score, ordenacao, empates, limite, zero votos. Int: pending2026 sem conciliacao (mesmo com votos locais), so adversarios, misto com exclusao de Solla/nao e geografia alheia. Lease advisory election-collections serializa os dois specs que tratam as colecoes eleitorais como test-owned (o import wipe-all apagaria as fixtures do novo spec no meio do assert, 48-way paralelo). Co-authored-by: Francisco Solla <fsolla@users.noreply.github.com> * refactor(A6): fixes do /simplify (3 reviewers paralelos) P1: campo coalition morto removido do input/select/mapping (sem consumidor). P1: hooks do lease com timeout explicito de 120s nos dois specs eleitorais (o wait advisory passa dos 10s default do Vitest sob contencao — flake em ambas as direcoes). P2: sonda de conciliacao via payload.count (idioma da casa), desempate final por candidateNumber (ordem deterministica), geography como prop na secao (sem lookup duplicado), casing Dep. Federal/Estadual alinhado, marcador 1313 via BASELINE_TICKET_2022, entrada no CHANGELOG. Declinados com justificativa: zones como tupla nao-vazia (churn em tipo compartilhado por assert provada no catalogo) e early-start da promise antes do Promise.all (loader-dentro-do-Suspense e o idioma da casa; ganho so em cache frio). Co-authored-by: Francisco Solla <fsolla@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Francisco Solla <fsolla@users.noreply.github.com>
8.7 KiB
Insight: oportunidades de dobradinha 2026
Status: em execução (Issue #27, claim 2026-07-31) — engenharia entra agora no estado "indisponível até 2026"; a ativação é automática quando a Fase 5 reconciliar runningAgain2026 (gatilho externo: TSE publica candidaturas — pós-15/08)
Atualizado em: 2026-07-31 (freshness audit da execução — ver "Revisão 2026-07-31")
Item do roadmap: docs/roadmap.md (Próximos — Demais itens abertos, A6)
Responsável: —
Revisão 2026-07-31 (freshness audit, execução da #27):
src/lib/electionInsights.tsfoi deletado (Pass 2 W4a, 2026-07-25). A matemática nasce em módulo puro novo:src/lib/ticketPartnerOpportunities.ts(identificadores em inglês; "dobradinha" fica só na copy pt-BR — a vertical operacional já resolveu o mesmo problema chamando a entidade destateDeputy).src/lib/electionAlliances.tsnão é criado. A taxonomia recomendada já existe no repo e se declarou para este uso:electionPartySpectrum.tsguarda a média contínua 0–10 de Bolognesi et al. (onda 2022) com o comentário "shared with future A6 tiers", ecampoParties.tsguarda o campo PT/Solla curado por ano (2026 incluso, FE Brasil). O tier da A6 compõe os dois — sem terceiro mapa.- Questões em aberto — resolvidas (ver seção própria abaixo).
- Posição na UI: o plano dizia "aba Visão geral", escrito antes das tabs pós-remodel. Hoje o detalhe tem aba Eleições dedicada aos derivados TSE (baseline + comparativo) — a lista de parceiros entra lá, streamed em Suspense próprio como as demais seções pesadas.
- Overview da lista — fora do escopo desta entrega. "Agregar top parceiros por território filtrado" foi pensado para o overview territorial pré-remodel; hoje o overview da lista é um strip de métricas (
MunicipalityListOverview), e um agregado que reage ao conjunto filtrado exigiria varredura estadual por request — padrão que o repo reserva a artefato CLI/build-time. Antes de 2026 carregado o agregado mostraria só o estado indisponível. Fica como follow-up possível depois que a Fase 5 popular 2026.- Cache: loader com
unstable_cachesob a tagelection-tse, como os irmãos. Quando a Fase 5 reconciliarrunningAgain2026(scriptscripts/reconcile-running-again.mjs, ainda a criar), o runbook dele termina comPOST /api/revalidate?tag=election-tse— mesmo passo pós-seed já documentado no AGENTS.md.
Revisão 2026-07-24: desde a M4, as dobradinhas OPERACIONAIS já existem no produto — entidade
stateDeputy+municipality.stateDeputies/leadership.stateDeputies+ vertical/campanha/dobradinhas. A6 vira a camada de insight TSE sobre esse registro: sugerir candidatos 2026 (por força local 2022 + alinhamento) para o staff registrar/priorizar comostateDeputy— não criar um segundo registro paralelo. Referências antigas a "núcleo" abaixo foram renomeadas para município.
Contexto
"Dobradinha" é a campanha conjunta entre dois candidatos que somam estrutura e votos num mesmo território. Sabendo, via baseline TSE 2022 + Fase 5 (ver baseline-eleitoral-tse.md), quais candidatos de 2022 voltam a concorrer em 2026 (runningAgain2026), podemos sugerir oportunidades de dobradinha por município/território — priorizando por (a) alinhamento político com a chapa PT/Solla e (b) força eleitoral local (votos recebidos ali em 2022). É o insight mais estratégico do conjunto e depende de dados de 2026, por isso é plano separado.
Objetivos
- Por município, listar candidatos que concorrem de novo em 2026 (
runningAgain2026=sim) com votos 2022 na geografia, partido/coligação e tier de alinhamento. - Ranquear por score combinando alinhamento (peso a definir) e força eleitoral local (votos 2022).
- Exibir no detalhe do município (aba Visão geral) a lista ranqueada de potenciais parceiros de dobradinha; no overview, agregar top parceiros por território filtrado.
- Habilitar só quando 2026 estiver carregado; enquanto não, mostrar "indisponível até a candidatura de 2026".
Decisões travadas
- Leitura derivada — sem escrita, sem
Consent, sem migration. - Depende do baseline TSE 2022 (Fase 1) e da Fase 5 (
runningAgain2026populado). - Sem PII — matching cross-ano via
identityKeypública (já no plano baseline). - i18n/naming seguem o AGENTS.md.
Questões em aberto — RESOLVIDAS (2026-07-31)
- Taxonomia de alinhamento político — RESOLVIDA. Tiers derivados dos dois módulos existentes, sem mapa novo:
aliado= partido do campo 2026 (isCampoParty(party, 2026)— FE Brasil: PT/PCdoB/PV);aliadoHistorico= bucketesquerdado espectro Bolognesi fora do campo;neutro= bucketcentroou partido desconhecido (falha "para o meio", nunca para aliado nem para adversário);adversario= bucketdireita. Cortes: os do espectro (esquerda ≤4,49 · centro 4,5–5,5 · direita ≥5,51), já pinados emelectionPartySpectrum.ts. - Fórmula do score — RESOLVIDA (default documentado, revisável com produto).
score = 0,6 * tierWeight + 0,4 * normalizedVotes, comtierWeight: aliado 1,0 · aliadoHistórico 0,7 · neutro 0,35 · adversário 0,1, enormalizedVotes = votos2022 / max(votos2022)dentro da geografia do município — leitura relativa e local, nunca % estadual (kernel dedocs/research/). Alinhamento pesa mais que força: dobradinha é primeiro decisão de confiança política, depois conta de votos. - Cargos — RESOLVIDO: só proporcionais (
deputado_federal+deputado_estadual, 1º turno). Solla (nº 1313, federal) é excluído — ele é a referência, não um parceiro. liderancavê? — RESOLVIDO pelo remodel:leaderé lockdown e a página do município já barra (noLeader). O insight é staff-only como todo dado eleitoral — não há variante de view model por papel.
Abordagem proposta (atualizada 2026-07-31)
flowchart LR
Cand["electionCandidate<br/>runningAgain2026=sim"]
Votes["electionCandidateVote 2022<br/>votos por geografia"]
Campo["campoParties.ts<br/>campo 2026"]
Spect["electionPartySpectrum.ts<br/>Bolognesi 2022"]
Score["computeTicketPartnerOpportunities(...)"]
Detail["Aba Eleições: lista ranqueada<br/>nome, cargo, partido, votos 2022, tier"]
Cand --> Score
Votes --> Score
Campo --> Score
Spect --> Score
Score --> Detail
- Puro
src/lib/ticketPartnerOpportunities.ts: tiers (campo + espectro), score, ordenação, labels pt-BR. Client-safe, testado em unit. - Loader
src/utilities/municipality/municipalityTicketPartnerData.ts(server-only):assertCanReadElectionData+unstable_cachetagelection-tse. Três queries pequenas — sonda "2026 reconciliado?" (payload.countderunningAgain2026 ∈ {sim,nao}), votos 2022 proporcionais na geografia, registrysimsó dos números com voto local. Sem sonda positiva →{ status: 'pending2026' }("indisponível até a candidatura de 2026"). - Componente
src/components/campaign/municipality/MunicipalityTicketPartnersCard.tsx(server): estados pending2026 / vazio / lista top-10 + link para/campanha/dobradinhas(registro operacional — não cria segundo registro paralelo). - Testes: unit do puro (tiers, score, ordenação, empates, zero votos) + int do loader (sem 2026 reconciliado →
pending2026; só adversários; misto com ordem/score; votos de outra geografia fora; Solla fora). O int novo eelectionResultsImport.int.spec.ts(que apaga TODA a tabela eleitoral) se serializam por lease advisoryelection-collections(tests/helpers/testDatabaseLease.ts).
Arquivos a criar/alterar
- Criar:
src/lib/ticketPartnerOpportunities.ts,src/utilities/municipality/municipalityTicketPartnerData.ts,src/components/campaign/municipality/MunicipalityTicketPartnersCard.tsx,tests/unit/ticketPartnerOpportunities.unit.spec.ts,tests/int/municipalityTicketPartnerData.int.spec.ts. - Alterar:
municipios/[slug]/MunicipalityDetailTabs.tsx(seção na aba Eleições),tests/int/electionResultsImport.int.spec.ts(lease compartilhado).
Dependências
- baseline-eleitoral-tse.md — Fase 1 (collections +
electionCandidateVote) e Fase 5 (runningAgain2026+identityKey). - 2026 publicado pelo TSE (externo; fora do nosso controle).
Não escopo
- Fechar dobradinhas (decisão política humana) — só sugerimos oportunidades, não fechamos alianças.
- Cruzar com pesquisa de intenção (domínio inexistente).
Referências
- baseline-eleitoral-tse.md — baseline + Fase 5 (2026)
- insight-inteligencia-competitiva.md — fornece o quadro competitivo base
- AGENTS.md — naming, modelo Municípios