mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-13 15:13:07 +00:00
feat(C157): relatório de sobreposição Solla × Ceuci em Salvador (Closes #979)
This commit is contained in:
parent
28460ad4ea
commit
021071543b
11 changed files with 2098 additions and 0 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -75,6 +75,8 @@ next-env.d.ts
|
|||
/data/ai-fill/
|
||||
# Câmara pilot media/JSON cache (pnpm camara:pilot — VOD MP4 + report, never commit)
|
||||
/data/camara/
|
||||
# Solla × Ceuci report HTML cache (scripts/build-solla-ceuci-salvador-report.mjs)
|
||||
/data/solla-ceuci-salvador/
|
||||
|
||||
# Local-only sensitive material (agents may read; never commit content)
|
||||
/private/**
|
||||
|
|
|
|||
1
docs/changelog/2026-09-14-c157.md
Normal file
1
docs/changelog/2026-09-14-c157.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
**C157 — Relatório: sobreposição Solla × Ceuci em Salvador 2022 (2026-09-14):** documento para a assessoria da campanha comparando a votação de 2022 de Jorge Solla (federal nº 1313; 27.264 votos em Salvador) e Ceuci Nunes (estadual nº 13192; 19.776 em Salvador, 36.992 no estado) nas 19 zonas eleitorais da capital e nos bairros. Entrega: [`docs/research/analise-sobreposicao-solla-ceuci-salvador-2022.pdf`](docs/research/analise-sobreposicao-solla-ceuci-salvador-2022.pdf) (15 páginas: capa, sumário executivo, contexto, método, 4 mapas — choropleth de cada candidato, classes de sobreposição por ZE e malha de bairros do IBGE Censo 2022 colorida pela ZE do centroide —, gráficos de barras e dispersão, 3 tabelas, leitura da ciência política na voz da persona Prof. Helena Rocha e plano do coordenador na voz da persona Nivaldo Cerqueira) + companion Markdown com números/proveniência + JSON de entrada com conferências cruzadas. Números: índice de sobreposição 0,678; Pearson 0,45 e Spearman 0,35 (N=19, com ressalva); núcleo compartilhado ZE 1/6/7/10/13; Ceuci supera Solla em ZE 1, 2, 6, 10 e 13; 53,5% do voto dela está na capital contra 21,1% do dele. Gerador `scripts/build-solla-ceuci-salvador-report.mjs` (HTML→PDF via Chromium do Playwright já instalado; sem dependência nova; sem banco; malha IBGE em cache gitignored), métricas puras em `scripts/lib/sollaCeuciSalvadorMetrics.mjs` com 8 unit tests, planos de intenção/impl em `docs/plans/relatorio-sobreposicao-solla-ceuci-salvador{,-impl}.md`; limite duro documentado no relatório (não existe voto por bairro/seção nos dados). Issue #979.
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
# Implementação — Relatório Solla × Ceuci em Salvador (2022)
|
||||
|
||||
Status: executado
|
||||
Atualizado em: 2026-09-14
|
||||
Issue: #979
|
||||
Intenção: docs/plans/relatorio-sobreposicao-solla-ceuci-salvador.md
|
||||
Appetite restante: 1 sessão
|
||||
|
||||
## Leitura da intenção
|
||||
|
||||
O entregável é o PDF; o gerador é meio. O relatório tem que funcionar impresso em A4, em preto-e-branco aceitável, com números conferíveis e sem promessa que os dados não sustentam (não há voto por bairro nem por eleitor). A análise política usa as duas personas como lentes declaradas — Helena Rocha (método) e Nivaldo Cerqueira (decisão) —, sem inventar números internos da campanha.
|
||||
|
||||
## Abordagem recomendada
|
||||
|
||||
**Opções**
|
||||
|
||||
- **A (recomendada): script Node único + HTML→PDF via Chromium do Playwright** (`@playwright/test` já é devDependency e os browsers estão instalados), com SVGs gerados das geometrias commitadas + malha de bairros do IBGE, e JSON de dados commitado. Sem dependência nova; o projeto já rejeitou lib de PDF server-side (`docs/plans/dossie-municipio.md`) e prefere CSS/print.
|
||||
- B: rota `/campanha` com print CSS — rejeitada: exige sessão autenticada, imprime Leaflet raster e não é um anexo entregável "amanhã" fora do app.
|
||||
- C: lib de PDF (pdfkit/react-pdf) — rejeitada: dependência nova + precedente contrário.
|
||||
|
||||
**Componentes/mudanças**
|
||||
|
||||
- `scripts/build-solla-ceuci-salvador-report.mjs` — baixa/simplifica a malha de bairros (cache `data/geometries/`), lê o JSON de dados + artefato de Solla, projeta SVGs, monta o HTML e imprime o PDF.
|
||||
- `docs/research/solla-ceuci-salvador-2022-dados.json` — entrada com proveniência (19 ZE: votos, válidos, posições, totais).
|
||||
- `docs/research/analise-sobreposicao-solla-ceuci-salvador-2022.md` + `.pdf` — entrega.
|
||||
- `docs/research/README.md` — registro na tabela; `docs/changelog/2026-09-14-c157.md` — contrato OPS44.
|
||||
- Sem `src/**` novo (não força suíte full), sem `package.json` (não força build/e2e curado).
|
||||
|
||||
**Fases verificáveis**
|
||||
|
||||
1. Exportar dados TSE 2022 de Salvador read-only (prod, só SELECT) → JSON; validar Solla contra o artefato (27.264) e Ceuci contra o total estadual conhecido (36.992) e contra 19.776 em Salvador.
|
||||
2. Baixar/simplificar malha de bairros do IBGE; conferir bbox de Salvador e contagem de bairros.
|
||||
3. Gerar HTML com mapas/tabelas; conferir em screenshot do Chromium (mapas legíveis, sem sobreposição de rótulos).
|
||||
4. Gerar PDF; conferir nº de páginas, fontes e tamanho; revisar o companion `.md`.
|
||||
5. Guards locais (`pnpm lint`, `pnpm format:check`, `gate:push`), commit, push, PR `Closes #979`, CI verde e merge (auto-merge nativo).
|
||||
|
||||
## Rabbit holes
|
||||
|
||||
- Mapa de bairros com geometria própria do IBGE mas voto por ZE: a legenda e a nota de método têm que dizer que a cor do bairro é a da ZE dele (centroide), nunca sugerir medição por bairro.
|
||||
- Projeção: não introduzir d3; equiretangular local com `cos(lat)` resolve Salvador.
|
||||
- Rótulos: não rotular 100+ bairros; rotular ZE e uma seleção de bairros fortes.
|
||||
|
||||
## Riscos
|
||||
|
||||
- Malha do IBGE indisponível no build (hoje acessível): o PDF já gerado é o entregável; o cache `data/geometries/` é local e gitignored.
|
||||
- 19 ZE é N pequeno para correlação: reportar Pearson e Spearman com ressalva explícita (não usar como probabilidade).
|
||||
- PDF pesado demais: simplificar malha de bairros e não embutir raster; meta < 5 MB.
|
||||
|
||||
## Aceite de engenharia
|
||||
|
||||
- Script roda de ponta a ponta sem banco; sem dependência nova.
|
||||
- PDF + companion `.md` + JSON de dados + changelog commitados.
|
||||
- `pnpm lint` e `pnpm format:check` verdes; PR com CI verde.
|
||||
|
||||
## Débitos + self-score
|
||||
|
||||
- O JSON de entrada foi extraído da base de produção (read-only) porque o CDN do TSE está bloqueado nesta rede; regenerar exige o mesmo caminho ou um seed local com os ZIPs. Registrado na proveniência do JSON.
|
||||
- Gerador não é chamado por alias `pnpm` (evita suíte full no CI); documentado no cabeçalho do script.
|
||||
75
docs/plans/relatorio-sobreposicao-solla-ceuci-salvador.md
Normal file
75
docs/plans/relatorio-sobreposicao-solla-ceuci-salvador.md
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
# Relatório — sobreposição Solla × Ceuci em Salvador (2022)
|
||||
|
||||
Status: rascunho
|
||||
Atualizado em: 2026-09-14
|
||||
Issue: #979
|
||||
Priority: P1
|
||||
Impeccable: N/A — documento impresso, não UI
|
||||
Rascunho UI: N/A — sem UI
|
||||
Appetite: 1 sessão (dados + mapas + PDF)
|
||||
Responsável: —
|
||||
|
||||
## Intenção
|
||||
|
||||
Produzir um relatório em PDF, para os assessores da campanha, comparando a votação de 2022 de **Jorge Solla** (deputado federal, PT 1313) e **Ceuci Nunes** (deputada estadual, PT 13192) nas 19 zonas eleitorais de Salvador e nos bairros, com mapas, tabelas e análise política de como a rede e a história de Ceuci — apoiadora do mandato — podem potencializar a campanha de 2026.
|
||||
|
||||
O uso é imediato: o coordenador e os assessores precisam decidir onde acionar Ceuci (eventos, agenda de saúde, mobilização de rede) por zona/bairro, com número na mão — não por sensação.
|
||||
|
||||
## Persona e fluxo
|
||||
|
||||
- **Quem usa:** coordenador-geral (persona Nivaldo Cerqueira — prioriza por % do NOSSO voto e decide agenda/material por fila de prioridade) e assessores territoriais (dossiê pré-agenda por território).
|
||||
- **Fluxo:** reunião de planejamento → escolha das zonas/bairros onde a sobreposição Solla×Ceuci é maior → encaixe da agenda de Ceuci e do material.
|
||||
- **Lente analítica:** persona Prof. Helena Rocha (cientista política) — conta do quociente, dominância×concentração, LQ, nunca % estadual absoluto; mapa que normaliza e mapa que não normaliza juntos.
|
||||
|
||||
## Objetivo e aceite
|
||||
|
||||
- PDF A4 em `docs/research/` com: sumário executivo; tabela por ZE (votos, % dos válidos, % do próprio voto, LQ, posição, sobreposição); tabela por bairro (bairros agrupados por ZE, fonte TRE-BA RA 02/2017); mapas de Salvador por ZE (votos de cada candidato + classes de sobreposição) e por bairro (malha IBGE Censo 2022); gráficos (barras por ZE, dispersão Solla×Ceuci); leitura da ciência política e plano do coordenador.
|
||||
- Companion `.md` com os números e a proveniência (PDF binário não é revisável no diff).
|
||||
- Gerador commitado (`scripts/*.mjs`) + JSON de entrada com proveniência; reproduzível sem banco e sem rede (JSON e cache já no repo/homeserver local).
|
||||
|
||||
## Dados (intenção)
|
||||
|
||||
- Solla: 2022 federal T1 nominal, por ZE de Salvador (19) — conferido contra o artefato commitado `bahia-federal-baseline.json`.
|
||||
- Ceuci: 2022 estadual T1 nominal, por ZE de Salvador (19) — TSE.
|
||||
- Tallies por ZE (válidos federal e estadual) para normalizar.
|
||||
- Bairros: lista oficial TRE-BA RA 02/2017 (commitada em `municipalityZoneNeighborhoods.ts`); malha IBGE Censo 2022 (download no build do relatório, cache gitignored).
|
||||
- **Limite duro:** o Teqo só tem município×zona — **não existe voto por seção/bairro**. O mapa de bairros pinta cada bairro com os números da sua ZE; o relatório diz isso na cara.
|
||||
|
||||
## Dados da decisão (literais)
|
||||
|
||||
- Ceuci 2022: 36.992 votos no estado, **19.776 em Salvador** (mais votada do PT na capital), não eleita; presidente da Bahiafarma desde 2023; descartou candidatura em 2026.
|
||||
- Solla 2022: 128.968 votos no estado; **27.264 em Salvador** (soma das 19 ZE no artefato).
|
||||
- Uso: Ceuci entra como **apoiadora do mandato**, sem candidatura própria — o relatório não a trata como candidata.
|
||||
|
||||
## Direção no codebase (hipótese)
|
||||
|
||||
- Script novo `scripts/build-solla-ceuci-salvador-report.mjs` (HTML→PDF via Chromium do Playwright já instalado; sem dependência nova), lendo o artefato de Solla e um JSON pequeno com Ceuci/tallies/posições.
|
||||
- Geometrias: `src/lib/geometries/bahia-municipality-zones.topo.json` (commitado) para o mapa de ZE; malha de bairros IBGE baixada pelo mesmo script (mesma fonte do `build-municipality-zone-geometries`), simplificada com `scripts/lib/topology.mjs`.
|
||||
- Cores: `src/lib/choroplethColorScale.ts` (dono da paleta) e projeção própria (equiretangular local; sem d3).
|
||||
- Destino: `docs/research/` (CI barato; `docs` fora da imagem Docker) + entrada em `docs/changelog/`.
|
||||
|
||||
## Dependências
|
||||
|
||||
- Issue #979. Sem dependência de código em andamento.
|
||||
|
||||
## Fora de escopo
|
||||
|
||||
- Voto por seção/bairro (exigiria `votacao_secao` + DE-PARA — E5, não implementado).
|
||||
- UI nova em `/campanha`; alteração de collections/migrations.
|
||||
- Publicação em `public/` (imagem de produção) — o PDF é entregue por anexo/PR.
|
||||
|
||||
## Rabbit holes de produto
|
||||
|
||||
- Tentar inferir voto por bairro por proporcionalidade: proibido (falsa precisão).
|
||||
- Inferir sobreposição de eleitor individual: não existe (voto não é observável por pessoa); só geografia.
|
||||
- Quociente estadual detalhado: tangencial ao uso (a decisão é territorial).
|
||||
|
||||
## Questões em aberto
|
||||
|
||||
- Nenhuma bloqueante; a validação é com os assessores depois da entrega.
|
||||
|
||||
## Referências
|
||||
|
||||
- Personas: `docs/research/persona-cientista-politico-campanha-ba.md`, `docs/research/persona-emendas-coordenador-campanha.md`.
|
||||
- Dados: `src/lib/electionAggregates/bahia-federal-baseline.json`, `src/lib/bahiaTseZones.ts`, `src/lib/municipalityZoneNeighborhoods.ts`.
|
||||
- Precedente de relatório: `docs/research/piloto-fonte-videos-camara.md` (C152).
|
||||
|
|
@ -57,3 +57,14 @@ Viabilidade da fonte do acervo de falas (Issue #954): 2–3 discursos de legisla
|
|||
| ----------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |
|
||||
| [`piloto-fonte-videos-camara.md`](piloto-fonte-videos-camara.md) | Respostas às 4 incógnitas da fonte (permanência do link, trechos em 55ª/56ª, segmentos Deep Infra, casamento antigo), custos e fallbacks | concluído 2026-09-12 |
|
||||
| [`piloto-fonte-videos-camara-impl.md`](../plans/piloto-fonte-videos-camara-impl.md) | Plano de implementação do piloto (script + lib pura + unit tests) | executado |
|
||||
|
||||
## Relatório — sobreposição Solla × Ceuci em Salvador (C157, 2026-09-14)
|
||||
|
||||
Comparação da votação de 2022 de Jorge Solla (federal, nº 1313) e Ceuci Nunes (estadual, nº 13192) nas 19 zonas eleitorais de Salvador e nos bairros: mapas por ZE e por bairro, tabelas de sobreposição e plano de campanha para acionar a rede e a memória de Ceuci (apoiadora do mandato, sem candidatura em 2026). Dados públicos TSE 2022; o limite "não existe voto por bairro" está documentado no próprio relatório.
|
||||
|
||||
| Artefato | O quê | Status |
|
||||
| -------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | ------------------- |
|
||||
| [`analise-sobreposicao-solla-ceuci-salvador-2022.pdf`](analise-sobreposicao-solla-ceuci-salvador-2022.pdf) | Relatório final em PDF (15 páginas) — mapas, tabelas, leitura da ciência política e plano | entregue 2026-09-14 |
|
||||
| [`analise-sobreposicao-solla-ceuci-salvador-2022.md`](analise-sobreposicao-solla-ceuci-salvador-2022.md) | Companion em Markdown com os números e a proveniência (os mapas vivem no PDF) | entregue 2026-09-14 |
|
||||
| [`solla-ceuci-salvador-2022-dados.json`](solla-ceuci-salvador-2022-dados.json) | Entrada do gerador: votos e tallies por ZE, com proveniência e conferências cruzadas | congelado |
|
||||
| [`../plans/relatorio-sobreposicao-solla-ceuci-salvador.md`](../plans/relatorio-sobreposicao-solla-ceuci-salvador.md) | Plano de intenção (+ [`impl`](../plans/relatorio-sobreposicao-solla-ceuci-salvador-impl.md)) | executado |
|
||||
|
|
|
|||
184
docs/research/analise-sobreposicao-solla-ceuci-salvador-2022.md
Normal file
184
docs/research/analise-sobreposicao-solla-ceuci-salvador-2022.md
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
# Solla × Ceuci em Salvador
|
||||
|
||||
**Onde as votações de 2022 se encontram — e como usar essa memória na campanha de 2026**
|
||||
Gerado em 14 de setembro de 2026 — dados públicos TSE 2022. Documento interno de campanha.
|
||||
|
||||
## Sumário executivo
|
||||
|
||||
- **Sobreposição parcial, com centro claro.** As duas distribuições de voto se sobrepõem em 67,8% (índice de sobreposição; 1,0 seriam distribuições idênticas), com correlação moderada entre as 19 zonas (Pearson 0,45; Spearman 0,35). O centro comum é ZE 1, ZE 6, ZE 7, ZE 10, ZE 13. Fora dele, as duas votações seguem lógicas diferentes — e é aí que está o trabalho de campo.
|
||||
- **Ceuci é candidata da capital; Solla, do estado.** 53,5% do voto de Ceuci (19.776 de 36.992) está em Salvador, contra 21,1% do voto de Solla (27.264 de 128.968). Na cidade, ela é concentrada: as 3 zonas mais fortes dela somam 44,8% do voto dela; as 3 de Solla somam 21,3%.
|
||||
- **Onde ela é maior que ele.** Ceuci supera Solla em 5 zonas — ZE 1 (2.374 × 1.298); ZE 2 (1.651 × 1.199); ZE 6 (1.632 × 1.475); ZE 10 (2.806 × 2.260); ZE 13 (3.670 × 1.721).
|
||||
- **Onde os dois somam mais.** As maiores somas Solla + Ceuci estão em ZE 13 (5.391), ZE 10 (5.066), ZE 1 (3.672), ZE 6 (3.107), ZE 7 (2.962) — os territórios onde uma agenda conjunta tem mais público potencial. Ela sozinha é mais forte em ZE 13 (3.670), ZE 10 (2.806), ZE 1 (2.374), ZE 2 (1.651), ZE 6 (1.632).
|
||||
- **Recomendação central.** Três movimentos: (1) defender os redutos compartilhados (ZE 1, ZE 6, ZE 7, ZE 10, ZE 13) com agenda e material conjuntos; (2) usar Ceuci como cabeça de ponte onde ela é acima da média e Solla abaixo (ZE 2); (3) acionar a rede dela como apoio declarado nas zonas de Base Solla (ZE 8, ZE 14, ZE 15, ZE 16, ZE 19) — sem tratá-la como candidata: ela declarou que não disputa 2026.
|
||||
|
||||
> **Como ler** Todos os números são oficiais (TSE 2022, 1º turno). O relatório compara duas candidaturas de cargos diferentes: Solla foi deputado federal (nº 1313) e Ceuci, deputada estadual (nº 13192). A sobreposição medida é entre as duas geografias de voto, não entre eleitores — não se observa quem votou em quem.
|
||||
|
||||
## Quem é Ceuci Nunes — e o que os números de 2022 dizem
|
||||
|
||||
Ceuci de Lima Xavier Nunes é médica infectologista e ficou 15 anos à frente do Instituto Couto Maia, referência estadual em infectologia — inclusive na pandemia de covid-19. Em 2022, foi candidata a deputada estadual pelo PT (nº 13192): recebeu 36.992 votos, não se elegeu, mas foi a mais votada do PT na capital, com 19.776 votos em Salvador. Desde março de 2023 preside a Bahiafarma, fundação estadual de medicamentos. Declarou à imprensa, em 2025, que não será candidata em 2026.
|
||||
|
||||
Para a campanha de Solla, isso define o papel dela: não é concorrente interna nem candidata a acomodar — é uma liderança com rede própria na saúde, voto concentrado na capital e história de gestão reconhecida. A pergunta deste relatório é onde essa rede encosta na votação de Solla e onde ela alcança eleitor que o mandato ainda não mobiliza.
|
||||
|
||||
A resposta tem dois lados. O primeiro: existe um centro comum (ZE 1, ZE 6, ZE 7, ZE 10, ZE 13) em que os dois estão acima da média — nesses territórios, a memória de Ceuci reforça o voto que Solla já tem. O segundo: a votação dela é bem mais concentrada que a dele. 61,4% do voto dela na cidade está em ZE 13 (3.670), ZE 10 (2.806), ZE 1 (2.374), ZE 2 (1.651), ZE 6 (1.632); a de Solla se espalha por toda a cidade, com presença forte em zonas periféricas onde ela quase não aparece (ZE 8, 14, 15, 16 e 19).
|
||||
|
||||
> **Alerta jurídico-eleitoral** Ceuci preside uma fundação estadual. Uso de imagem, agenda e declarações em ano eleitoral deve passar pelo jurídico da campanha antes de virar material. Este relatório é análise de dados públicos — não é parecer jurídico.
|
||||
|
||||
## Método, fontes e limites
|
||||
|
||||
Fonte: resultados oficiais do TSE para 2022 (votação nominal de 1º turno por município e zona eleitoral). Solla: deputado federal nº 1313 (PT), 128.968 votos no estado e 27.264 em Salvador. Ceuci: deputada estadual nº 13192 (PT), 36.992 votos no estado e 19.776 em Salvador. Salvador é lida pelas suas 19 zonas eleitorais (ZE 1–19).
|
||||
|
||||
Os valores foram conferidos contra duas referências: o artefato federal já commitado no Teqo (votação de Solla por zona, conferida zona a zona) e os totais oficiais de Ceuci (36.992 no estado; 19.776 em Salvador).
|
||||
|
||||
Bairros: a lista de bairros por zona é a circunscrição oficial do TRE-BA (Resolução Administrativa nº 2/2017, Anexo I). O mapa de bairros usa a malha de bairros do IBGE (Censo 2022) e pinta cada bairro com os números da zona que contém seu centroide.
|
||||
|
||||
Força relativa: o LQ (quociente local) compara a fatia da zona no voto do candidato com a fatia da zona nos votos válidos. LQ = 1 é exatamente a média do candidato; acima de 1, a zona é relativamente forte para ele.
|
||||
|
||||
Sobreposição: o índice soma, zona a zona, o menor valor entre as duas fatias de voto (0 a 1). A correlação mede se as duas votações sobem e descem juntas entre as zonas — com 19 zonas, é indício, não probabilidade.
|
||||
|
||||
> **Limite duro: não existe voto por bairro** Os dados disponíveis têm votação por município e zona eleitoral. Não há voto por seção, local de votação ou bairro — nenhum número deste relatório deve ser lido como votação de um bairro. Bairro aqui é a lista oficial de bairros que compõem a zona. O mapa de bairros é ilustrativo: mostra a malha e a classe da zona de cada bairro.
|
||||
|
||||
## Mapas
|
||||
|
||||
_(mapa/gráfico disponível no PDF)_
|
||||
|
||||
_(mapa/gráfico disponível no PDF)_
|
||||
|
||||
_(mapa/gráfico disponível no PDF)_
|
||||
|
||||
_(mapa/gráfico disponível no PDF)_
|
||||
|
||||
## Votos por zona e dispersão
|
||||
|
||||
_(mapa/gráfico disponível no PDF)_
|
||||
|
||||
_(mapa/gráfico disponível no PDF)_
|
||||
|
||||
## Tabelas
|
||||
|
||||
**Votação 2022 por zona eleitoral de Salvador (ordem de ZE)**
|
||||
|
||||
| ZE | Solla | Ceuci | Soma | % válidos Solla | % válidos Ceuci | Solla no estado | Ceuci no estado |
|
||||
| ----- | ----- | ----- | ----- | --------------- | --------------- | --------------- | --------------- |
|
||||
| ZE 1 | 1.298 | 2.374 | 3.672 | 2,4% | 4,6% | 8º de 547 | 3º de 690 |
|
||||
| ZE 2 | 1.199 | 1.651 | 2.850 | 2,0% | 2,9% | 11º de 550 | 8º de 710 |
|
||||
| ZE 3 | 1.257 | 474 | 1.731 | 1,8% | 0,7% | 13º de 582 | 35º de 698 |
|
||||
| ZE 4 | 1.531 | 310 | 1.841 | 2,0% | 0,4% | 12º de 551 | 53º de 710 |
|
||||
| ZE 5 | 893 | 632 | 1.525 | 1,6% | 1,2% | 21º de 548 | 19º de 704 |
|
||||
| ZE 6 | 1.475 | 1.632 | 3.107 | 2,3% | 2,6% | 8º de 571 | 6º de 704 |
|
||||
| ZE 7 | 1.774 | 1.188 | 2.962 | 2,8% | 2,0% | 9º de 568 | 6º de 703 |
|
||||
| ZE 8 | 1.455 | 348 | 1.803 | 2,2% | 0,5% | 11º de 587 | 40º de 703 |
|
||||
| ZE 9 | 1.265 | 532 | 1.797 | 2,1% | 0,9% | 11º de 568 | 23º de 681 |
|
||||
| ZE 10 | 2.260 | 2.806 | 5.066 | 2,4% | 3,1% | 8º de 588 | 4º de 751 |
|
||||
| ZE 11 | 1.460 | 335 | 1.795 | 1,9% | 0,5% | 12º de 575 | 46º de 723 |
|
||||
| ZE 12 | 1.436 | 983 | 2.419 | 1,8% | 1,3% | 16º de 591 | 12º de 720 |
|
||||
| ZE 13 | 1.721 | 3.670 | 5.391 | 2,2% | 5,0% | 9º de 554 | 3º de 699 |
|
||||
| ZE 14 | 1.682 | 572 | 2.254 | 2,3% | 0,8% | 10º de 578 | 25º de 719 |
|
||||
| ZE 15 | 1.289 | 286 | 1.575 | 2,2% | 0,5% | 9º de 542 | 41º de 661 |
|
||||
| ZE 16 | 1.643 | 653 | 2.296 | 2,4% | 1,0% | 7º de 571 | 22º de 702 |
|
||||
| ZE 17 | 990 | 342 | 1.332 | 1,6% | 0,6% | 17º de 554 | 41º de 687 |
|
||||
| ZE 18 | 860 | 437 | 1.297 | 1,8% | 0,9% | 12º de 565 | 26º de 665 |
|
||||
| ZE 19 | 1.776 | 551 | 2.327 | 2,2% | 0,7% | 9º de 584 | 34º de 745 |
|
||||
|
||||
**Força relativa e sobreposição por zona (LQ = quociente local)**
|
||||
|
||||
| ZE | % do voto Solla | % do voto Ceuci | LQ Solla | LQ Ceuci | Sobreposição | Classe |
|
||||
| ----- | --------------- | --------------- | -------- | -------- | ------------ | -------------------- |
|
||||
| ZE 1 | 4,8% | 12,0% | 1,15 | 2,86 | 4,8% | Reduto compartilhado |
|
||||
| ZE 2 | 4,4% | 8,3% | 0,93 | 1,79 | 4,4% | Ponte Ceuci |
|
||||
| ZE 3 | 4,6% | 2,4% | 0,86 | 0,44 | 2,4% | Disputa ampla |
|
||||
| ZE 4 | 5,6% | 1,6% | 0,95 | 0,27 | 1,6% | Disputa ampla |
|
||||
| ZE 5 | 3,3% | 3,2% | 0,74 | 0,73 | 3,2% | Disputa ampla |
|
||||
| ZE 6 | 5,4% | 8,3% | 1,08 | 1,63 | 5,4% | Reduto compartilhado |
|
||||
| ZE 7 | 6,5% | 6,0% | 1,32 | 1,22 | 6,0% | Reduto compartilhado |
|
||||
| ZE 8 | 5,3% | 1,8% | 1,02 | 0,34 | 1,8% | Base Solla |
|
||||
| ZE 9 | 4,6% | 2,7% | 0,99 | 0,56 | 2,7% | Disputa ampla |
|
||||
| ZE 10 | 8,3% | 14,2% | 1,12 | 1,92 | 8,3% | Reduto compartilhado |
|
||||
| ZE 11 | 5,4% | 1,7% | 0,92 | 0,29 | 1,7% | Disputa ampla |
|
||||
| ZE 12 | 5,3% | 5,0% | 0,87 | 0,82 | 5,0% | Disputa ampla |
|
||||
| ZE 13 | 6,3% | 18,6% | 1,06 | 3,12 | 6,3% | Reduto compartilhado |
|
||||
| ZE 14 | 6,2% | 2,9% | 1,09 | 0,51 | 2,9% | Base Solla |
|
||||
| ZE 15 | 4,7% | 1,4% | 1,05 | 0,33 | 1,4% | Base Solla |
|
||||
| ZE 16 | 6,0% | 3,3% | 1,16 | 0,64 | 3,3% | Base Solla |
|
||||
| ZE 17 | 3,6% | 1,7% | 0,75 | 0,35 | 1,7% | Disputa ampla |
|
||||
| ZE 18 | 3,2% | 2,2% | 0,85 | 0,58 | 2,2% | Disputa ampla |
|
||||
| ZE 19 | 6,5% | 2,8% | 1,02 | 0,44 | 2,8% | Base Solla |
|
||||
|
||||
**Bairros oficiais por zona eleitoral (TRE-BA RA 02/2017) e votos da ZE**
|
||||
|
||||
| ZE | Classe | Solla | Ceuci | Bairros da zona |
|
||||
| ----- | -------------------- | ----- | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| ZE 13 | Reduto compartilhado | 1.721 | 3.670 | Caminho das Árvores · Itaigara · Nordeste de Amaralina · Pituba · Santa Cruz · Vale das Pedrinhas |
|
||||
| ZE 10 | Reduto compartilhado | 2.260 | 2.806 | Bairro da Paz · Boca do Rio · Costa Azul · Imbuí · Jardim Armação · Patamares · Piatã · Pituaçu · STIEP |
|
||||
| ZE 1 | Reduto compartilhado | 1.298 | 2.374 | Alto das Pombas · Barra · Calabar · Canela · Centro · Centro Histórico · Garcia · Graça · Vitória |
|
||||
| ZE 6 | Reduto compartilhado | 1.475 | 1.632 | Acupe · Boa Vista de Brotas · Brotas · Candeal · Engenho Velho de Brotas |
|
||||
| ZE 7 | Reduto compartilhado | 1.774 | 1.188 | Barbalho · Barris · Comércio · Cosme de Farias · Luiz Anselmo · Macaúbas · Matatu · Nazaré · Santo Agostinho · Santo Antônio · Saúde · Tororó · Vila Laura |
|
||||
| ZE 2 | Ponte Ceuci | 1.199 | 1.651 | Amaralina · Chapada do Rio Vermelho · Engenho Velho da Federação · Federação · Ondina · Rio Vermelho |
|
||||
| ZE 12 | Disputa ampla | 1.436 | 983 | Aeroporto · Alto do Coqueirinho · Areia Branca · Itapuã · Itinga · Jardim das Margaridas · São Cristóvão · Stella Maris |
|
||||
| ZE 19 | Base Solla | 1.776 | 551 | Boca da Mata · Cajazeiras X · Cajazeiras XI · Cassange · Fazenda Grande I · Fazenda Grande II · Fazenda Grande III · Fazenda Grande IV · Jaguaripe I · Jardim Nova Esperança · Mussurunga · Nova Brasília · Nova Esperança · Novo Marotinho · Trobogy |
|
||||
| ZE 16 | Base Solla | 1.643 | 653 | Cabula VI · Canabrava · Centro Administrativo da Bahia · Doron · Narandiba · Nova Sussuarana · Pernambués · Saboeiro · São Rafael · Saramandaia · Vale dos Lagos |
|
||||
| ZE 14 | Base Solla | 1.682 | 572 | Arenoso · Novo Horizonte · São Marcos · Sussuarana · Tancredo Neves |
|
||||
| ZE 4 | Disputa ampla | 1.531 | 310 | Coutos · Fazenda Coutos · Ilha de Bom Jesus dos Passos · Ilha de Maré · Ilha dos Frades · Nova Constituinte · Paripe · Periperi (parte ao norte da Rua das Pedrinhas) · São Tomé |
|
||||
| ZE 8 | Base Solla | 1.455 | 348 | Cajazeiras II · Cajazeiras IV · Cajazeiras V · Cajazeiras VI · Cajazeiras VII · Cajazeiras VIII · Campinas de Pirajá · Marechal Rondon · Moradas da Lagoa · Palestina · Pirajá · Valéria |
|
||||
| ZE 9 | Disputa ampla | 1.265 | 532 | Boa Viagem · Bonfim · Jardim Cruzeiro · Mangueira · Massaranduba · Monte Serrat · Ribeira · Santa Luzia · Uruguai · Vila Ruy Barbosa |
|
||||
| ZE 11 | Disputa ampla | 1.460 | 335 | Águas Claras · Calabetão · Castelo Branco · Dom Avelar · Granjas Rurais Presidente Vargas · Jardim Cajazeiras · Jardim Santo Inácio · Pau da Lima · Porto Seco Pirajá · Sete de Abril · Vila Canária |
|
||||
| ZE 3 | Disputa ampla | 1.257 | 474 | Baixa de Quintas · Cidade Nova · Fazenda Grande do Retiro · IAPI · Pau Miúdo · Pero Vaz · Santa Mônica |
|
||||
| ZE 15 | Base Solla | 1.289 | 286 | Arraial do Retiro · Boa Vista de São Caetano · Bom Juá · Capelinha · Lobato · São Caetano |
|
||||
| ZE 5 | Disputa ampla | 893 | 632 | Barreiras · Cabula · Engomadeira · Mata Escura · Resgate · Retiro · São Gonçalo |
|
||||
| ZE 17 | Disputa ampla | 990 | 342 | Alto da Terezinha · Alto do Cabrito · Itacaranha · Periperi (parte ao sul da Rua das Pedrinhas) · Plataforma · Praia Grande · Rio Sena · São João do Cabrito |
|
||||
| ZE 18 | Disputa ampla | 860 | 437 | Caixa D'água · Calçada · Caminho de Areia · Curuzu · Lapinha · Liberdade · Mares · Roma |
|
||||
|
||||
## Leitura da ciência política
|
||||
|
||||
_Lente da persona pesquisadora — Prof. Helena Rocha (sintética)_
|
||||
|
||||
A conta do quociente. Em 2022, a Bahia teve 7.175.437 votos válidos para deputado estadual e 63 cadeiras — quociente eleitoral de aproximadamente 113.896 votos. Ceuci fez 36.992 (cerca de um terço de um quociente): não se elegeu sozinha, mas construiu uma base de capital que, em 2026, vale como rede de apoio para um deputado federal que precisa de 150 mil votos.
|
||||
|
||||
Dominância e concentração são coisas diferentes. Ceuci tem dominância concentrada: LQ 3,12 na ZE 13, LQ 2,86 na ZE 1, e 44,8% do voto dela nas três maiores zonas. Solla tem dominância dispersa: as três maiores zonas dele somam 21,3%. Não é defeito de um nem virtude do outro — é a diferença entre uma candidata de uma cidade e um deputado de um estado. A estratégia mora no cruzamento: nos redutos compartilhados, somar; nas zonas de Ceuci sem Solla, transferir presença; nas de Solla sem Ceuci, não forçar.
|
||||
|
||||
Eleito é o que dispersa a tempo. Solla já dispersa no estado; o risco em Salvador é concentrar esforço onde ele já vai bem. As zonas mais fortes de Ceuci (1, 2, 6, 10 e 13) são urbanas, de classe média e de serviços — não são o reduto histórico do mandato, e é exatamente aí que a rede dela muda o patamar.
|
||||
|
||||
Campanha não persuade; organiza e orienta. A função de Ceuci não é converter adversários: é orientar quem já votou nela a votar 1313. São quase 37 mil pessoas no estado — 19.776 só na capital — e a literatura de campanha mostra que contato pessoal via rede de confiança é o que mobiliza. O custo é baixo porque a lista de apoiadores de 2022 existe.
|
||||
|
||||
O mandato é a campanha. A memória que Ceuci carrega é de gestão e de saúde pública (Couto Maia, pandemia, medicamentos). O material e os eventos devem falar de entrega e continuidade do mandato de Solla — não de cargo, nem de futura candidatura dela.
|
||||
|
||||
> **O que é dado e o que é leitura** Dado: todos os números TSE deste relatório, conferidos na fonte. Leitura: as hipóteses de transferência de voto e os papéis sugeridos para Ceuci. Nenhuma transferência de voto é medida aqui — isso só se verifica na urna de 2026.
|
||||
|
||||
## Plano do coordenador
|
||||
|
||||
_Lente da persona coordenadora — Nivaldo Cerqueira (sintética, ancorada em evidência real)_
|
||||
|
||||
O critério é o de sempre: % do nosso voto decide a fila, e a agenda segue a fila. A tabela abaixo traduz a análise em quatro filas de trabalho. As zonas de prioridade 1 e 2 concentram 49,0% da soma das duas votações na cidade — é onde o esforço conjunto tem retorno mais claro.
|
||||
|
||||
Cuidado com fogo amigo: Ceuci não é candidata e não deve virar palanque paralelo. O material é de apoio ao mandato; o alinhamento com o PT estadual evita disputa de narrativa.
|
||||
|
||||
**Fila de prioridade da campanha (critério: % do nosso voto e classe de sobreposição)**
|
||||
|
||||
| Prioridade | Zonas | Por quê | Ação com Ceuci |
|
||||
| ---------------------- | -------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| 1 — Defender | ZE 1, ZE 6, ZE 7, ZE 10, ZE 13 | Redutos compartilhados: os dois acima da média; maior soma de votos. | Evento conjunto por zona (saúde + prestação de contas); material “Ceuci apoia Solla” na porta das unidades, rádio e digital geolocalizado. |
|
||||
| 2 — Ponte Ceuci | ZE 2 | Ela acima da média, ele abaixo: rede dela alcança eleitor que o mandato ainda não mobiliza. | Agenda dela com lideranças de saúde e comunitárias; Solla entra no fim; meta: elevar o LQ de Solla na zona para ≥ 1,0. |
|
||||
| 3 — Consolidar | ZE 8, ZE 14, ZE 15, ZE 16, ZE 19 | Base Solla: ele acima da média; ela tem voto residual. | Apoio declarado dela em material e visitas pontuais onde houver rede de saúde; não gastar agenda dela em zona de baixo retorno. |
|
||||
| 4 — Decidir por volume | ZE 3, ZE 4, ZE 5, ZE 9, ZE 11, ZE 12, ZE 17, ZE 18 | Ambos abaixo da média; decidir pelo volume absoluto (ex.: ZE 12 e ZE 4 somam mais que ZE 5 e ZE 18). | Sem agenda dedicada dela; entra apenas em ação municipal de saúde (mutirão, anúncio de política pública). |
|
||||
|
||||
- **Semana 1 — rede.** Fechar a lista de convites da rede de Ceuci (saúde, profissionais, apoiadores de 2022) e cruzar com as zonas 1, 2, 6, 10 e 13. Sem lista, não há evento.
|
||||
- **Semana 2 — redutos.** Dois eventos conjuntos: ZE 13 (5.391 votos somados) e ZE 10 (5.066). Formato: agenda de saúde + prestação de contas do mandato.
|
||||
- **Semana 3 — capital.** ZE 1 (3.672) e ZE 6 (3.107). Material “Ceuci apoia Solla” na porta das unidades e no digital geolocalizado.
|
||||
- **Semana 4 — ponte.** ZE 2 (2.850): agenda dela com lideranças comunitárias; Solla entra no fim. Balanço e repriorização com os deltas do campo.
|
||||
|
||||
> **Como usar este documento na assessoria** A tabela por bairro (seção Tabelas) é o anexo do dossiê pré-agenda: antes de qualquer visita, confira a zona do bairro e a classe. Nas zonas 1 e 2, a presença de Ceuci é o argumento; nas zonas 3 e 4, o mandato fala sozinho.
|
||||
|
||||
## Anexo — fontes e reprodução
|
||||
|
||||
- **Dados eleitorais.** TSE — Resultados 2022, votação nominal de 1º turno por município e zona (arquivos de dados abertos). Extração de 14/09/2026, conferida contra o artefato interno do Teqo e contra os totais oficiais.
|
||||
- **Bairros.** TRE-BA, Resolução Administrativa nº 2/2017, Anexo I (circunscrição das zonas por bairro). Malha de bairros: IBGE, Censo 2022 (shapefile BA_bairros_CD2022).
|
||||
- **Biografia de Ceuci.** Registro público: candidatura 2022 (TSE), votação de 36.992/19.776, presidência da Bahiafarma (2023) e declaração de não candidatura em 2026 (imprensa).
|
||||
- **Reprodução.** NODE_OPTIONS="--no-deprecation --import=tsx/esm" node scripts/build-solla-ceuci-salvador-report.mjs — lê o JSON de entrada commitado e regenera o PDF e este Markdown. Sem banco de dados.
|
||||
- **Aviso.** Documento interno de campanha. Não contém dados pessoais; usa apenas dados públicos de votação. Os mapas de zona são derivados de malha de bairros (aproximação) — não são limites oficiais do TSE.
|
||||
|
||||
---
|
||||
|
||||
Proveniência dos dados: TSE — Resultados 2022 (votação nominal por município e zona; detalhe da votação por município e zona). Extração: 2026-09-14. Base de produção do Teqo (teqo_1313) via SELECT read-only — o CDN de dados abertos do TSE está bloqueado nesta rede.
|
||||
|
||||
- Solla Salvador (soma das 19 ZE) = 27.264 = soma do artefato commitado src/lib/electionAggregates/bahia-federal-baseline.json (conferida zona a zona).
|
||||
- Ceuci estado = 36.992 = total_votes_state do registro TSE e valor noticiado na imprensa.
|
||||
- Ceuci Salvador (soma das 19 ZE) = 19.776 = valor noticiado na imprensa (mais votada do PT na capital).
|
||||
BIN
docs/research/analise-sobreposicao-solla-ceuci-salvador-2022.pdf
Normal file
BIN
docs/research/analise-sobreposicao-solla-ceuci-salvador-2022.pdf
Normal file
Binary file not shown.
378
docs/research/solla-ceuci-salvador-2022-dados.json
Normal file
378
docs/research/solla-ceuci-salvador-2022-dados.json
Normal file
|
|
@ -0,0 +1,378 @@
|
|||
{
|
||||
"year": 2022,
|
||||
"turn": 1,
|
||||
"city": {
|
||||
"name": "Salvador",
|
||||
"tseCityCode": "38490",
|
||||
"ibgeCode": "2927408"
|
||||
},
|
||||
"offices": {
|
||||
"federal": "deputado_federal",
|
||||
"state": "deputado_estadual"
|
||||
},
|
||||
"candidates": {
|
||||
"solla": {
|
||||
"candidateNumber": 1313,
|
||||
"office": "deputado_federal",
|
||||
"urnaName": "JORGE SOLLA",
|
||||
"completeName": "JORGE JOSE SANTOS PEREIRA SOLLA",
|
||||
"party": "PT",
|
||||
"coalition": "FEDERAÇÃO",
|
||||
"elected": true,
|
||||
"stateVotes": 128968
|
||||
},
|
||||
"ceuci": {
|
||||
"candidateNumber": 13192,
|
||||
"office": "deputado_estadual",
|
||||
"urnaName": "DR. CEUCI",
|
||||
"completeName": "CEUCI DE LIMA XAVIER NUNES",
|
||||
"party": "PT",
|
||||
"coalition": "FEDERAÇÃO",
|
||||
"elected": false,
|
||||
"stateVotes": 36992
|
||||
}
|
||||
},
|
||||
"stateContext": {
|
||||
"federalValid": 7605138,
|
||||
"stateValid": 7175437,
|
||||
"federalCandidates": 669,
|
||||
"stateCandidates": 847
|
||||
},
|
||||
"salvadorTotals": {
|
||||
"sollaVotes": 27264,
|
||||
"ceuciVotes": 19776,
|
||||
"federalValid": 1290350,
|
||||
"stateValid": 1232082,
|
||||
"federalComparecimento": 1627906,
|
||||
"stateComparecimento": 1627906
|
||||
},
|
||||
"zones": [
|
||||
{
|
||||
"zoneNumber": 1,
|
||||
"sollaVotes": 1298,
|
||||
"ceuciVotes": 2374,
|
||||
"federalValid": 53575,
|
||||
"stateValid": 51697,
|
||||
"federalComparecimento": 62489,
|
||||
"stateComparecimento": 62489,
|
||||
"sollaFederalRank": 8,
|
||||
"federalCandidates": 547,
|
||||
"ceuciStateRank": 3,
|
||||
"stateCandidates": 690
|
||||
},
|
||||
{
|
||||
"zoneNumber": 2,
|
||||
"sollaVotes": 1199,
|
||||
"ceuciVotes": 1651,
|
||||
"federalValid": 61247,
|
||||
"stateValid": 57599,
|
||||
"federalComparecimento": 74547,
|
||||
"stateComparecimento": 74547,
|
||||
"sollaFederalRank": 11,
|
||||
"federalCandidates": 550,
|
||||
"ceuciStateRank": 8,
|
||||
"stateCandidates": 710
|
||||
},
|
||||
{
|
||||
"zoneNumber": 3,
|
||||
"sollaVotes": 1257,
|
||||
"ceuciVotes": 474,
|
||||
"federalValid": 69090,
|
||||
"stateValid": 67283,
|
||||
"federalComparecimento": 91018,
|
||||
"stateComparecimento": 91018,
|
||||
"sollaFederalRank": 13,
|
||||
"federalCandidates": 582,
|
||||
"ceuciStateRank": 35,
|
||||
"stateCandidates": 698
|
||||
},
|
||||
{
|
||||
"zoneNumber": 4,
|
||||
"sollaVotes": 1531,
|
||||
"ceuciVotes": 310,
|
||||
"federalValid": 76325,
|
||||
"stateValid": 72120,
|
||||
"federalComparecimento": 100352,
|
||||
"stateComparecimento": 100352,
|
||||
"sollaFederalRank": 12,
|
||||
"federalCandidates": 551,
|
||||
"ceuciStateRank": 53,
|
||||
"stateCandidates": 710
|
||||
},
|
||||
{
|
||||
"zoneNumber": 5,
|
||||
"sollaVotes": 893,
|
||||
"ceuciVotes": 632,
|
||||
"federalValid": 57013,
|
||||
"stateValid": 54068,
|
||||
"federalComparecimento": 71095,
|
||||
"stateComparecimento": 71095,
|
||||
"sollaFederalRank": 21,
|
||||
"federalCandidates": 548,
|
||||
"ceuciStateRank": 19,
|
||||
"stateCandidates": 704
|
||||
},
|
||||
{
|
||||
"zoneNumber": 6,
|
||||
"sollaVotes": 1475,
|
||||
"ceuciVotes": 1632,
|
||||
"federalValid": 64496,
|
||||
"stateValid": 62230,
|
||||
"federalComparecimento": 79572,
|
||||
"stateComparecimento": 79572,
|
||||
"sollaFederalRank": 8,
|
||||
"federalCandidates": 571,
|
||||
"ceuciStateRank": 6,
|
||||
"stateCandidates": 704
|
||||
},
|
||||
{
|
||||
"zoneNumber": 7,
|
||||
"sollaVotes": 1774,
|
||||
"ceuciVotes": 1188,
|
||||
"federalValid": 63799,
|
||||
"stateValid": 60694,
|
||||
"federalComparecimento": 77593,
|
||||
"stateComparecimento": 77593,
|
||||
"sollaFederalRank": 9,
|
||||
"federalCandidates": 568,
|
||||
"ceuciStateRank": 6,
|
||||
"stateCandidates": 703
|
||||
},
|
||||
{
|
||||
"zoneNumber": 8,
|
||||
"sollaVotes": 1455,
|
||||
"ceuciVotes": 348,
|
||||
"federalValid": 67371,
|
||||
"stateValid": 63750,
|
||||
"federalComparecimento": 87276,
|
||||
"stateComparecimento": 87276,
|
||||
"sollaFederalRank": 11,
|
||||
"federalCandidates": 587,
|
||||
"ceuciStateRank": 40,
|
||||
"stateCandidates": 703
|
||||
},
|
||||
{
|
||||
"zoneNumber": 9,
|
||||
"sollaVotes": 1265,
|
||||
"ceuciVotes": 532,
|
||||
"federalValid": 60344,
|
||||
"stateValid": 59204,
|
||||
"federalComparecimento": 79818,
|
||||
"stateComparecimento": 79818,
|
||||
"sollaFederalRank": 11,
|
||||
"federalCandidates": 568,
|
||||
"ceuciStateRank": 23,
|
||||
"stateCandidates": 681
|
||||
},
|
||||
{
|
||||
"zoneNumber": 10,
|
||||
"sollaVotes": 2260,
|
||||
"ceuciVotes": 2806,
|
||||
"federalValid": 95719,
|
||||
"stateValid": 90859,
|
||||
"federalComparecimento": 113017,
|
||||
"stateComparecimento": 113017,
|
||||
"sollaFederalRank": 8,
|
||||
"federalCandidates": 588,
|
||||
"ceuciStateRank": 4,
|
||||
"stateCandidates": 751
|
||||
},
|
||||
{
|
||||
"zoneNumber": 11,
|
||||
"sollaVotes": 1460,
|
||||
"ceuciVotes": 335,
|
||||
"federalValid": 75491,
|
||||
"stateValid": 71434,
|
||||
"federalComparecimento": 97411,
|
||||
"stateComparecimento": 97411,
|
||||
"sollaFederalRank": 12,
|
||||
"federalCandidates": 575,
|
||||
"ceuciStateRank": 46,
|
||||
"stateCandidates": 723
|
||||
},
|
||||
{
|
||||
"zoneNumber": 12,
|
||||
"sollaVotes": 1436,
|
||||
"ceuciVotes": 983,
|
||||
"federalValid": 78414,
|
||||
"stateValid": 74998,
|
||||
"federalComparecimento": 97061,
|
||||
"stateComparecimento": 97061,
|
||||
"sollaFederalRank": 16,
|
||||
"federalCandidates": 591,
|
||||
"ceuciStateRank": 12,
|
||||
"stateCandidates": 720
|
||||
},
|
||||
{
|
||||
"zoneNumber": 13,
|
||||
"sollaVotes": 1721,
|
||||
"ceuciVotes": 3670,
|
||||
"federalValid": 76839,
|
||||
"stateValid": 73307,
|
||||
"federalComparecimento": 90093,
|
||||
"stateComparecimento": 90093,
|
||||
"sollaFederalRank": 9,
|
||||
"federalCandidates": 554,
|
||||
"ceuciStateRank": 3,
|
||||
"stateCandidates": 699
|
||||
},
|
||||
{
|
||||
"zoneNumber": 14,
|
||||
"sollaVotes": 1682,
|
||||
"ceuciVotes": 572,
|
||||
"federalValid": 72988,
|
||||
"stateValid": 69464,
|
||||
"federalComparecimento": 94242,
|
||||
"stateComparecimento": 94242,
|
||||
"sollaFederalRank": 10,
|
||||
"federalCandidates": 578,
|
||||
"ceuciStateRank": 25,
|
||||
"stateCandidates": 719
|
||||
},
|
||||
{
|
||||
"zoneNumber": 15,
|
||||
"sollaVotes": 1289,
|
||||
"ceuciVotes": 286,
|
||||
"federalValid": 57956,
|
||||
"stateValid": 53814,
|
||||
"federalComparecimento": 74565,
|
||||
"stateComparecimento": 74565,
|
||||
"sollaFederalRank": 9,
|
||||
"federalCandidates": 542,
|
||||
"ceuciStateRank": 41,
|
||||
"stateCandidates": 661
|
||||
},
|
||||
{
|
||||
"zoneNumber": 16,
|
||||
"sollaVotes": 1643,
|
||||
"ceuciVotes": 653,
|
||||
"federalValid": 67117,
|
||||
"stateValid": 64030,
|
||||
"federalComparecimento": 84583,
|
||||
"stateComparecimento": 84583,
|
||||
"sollaFederalRank": 7,
|
||||
"federalCandidates": 571,
|
||||
"ceuciStateRank": 22,
|
||||
"stateCandidates": 702
|
||||
},
|
||||
{
|
||||
"zoneNumber": 17,
|
||||
"sollaVotes": 990,
|
||||
"ceuciVotes": 342,
|
||||
"federalValid": 62509,
|
||||
"stateValid": 60593,
|
||||
"federalComparecimento": 85769,
|
||||
"stateComparecimento": 85769,
|
||||
"sollaFederalRank": 17,
|
||||
"federalCandidates": 554,
|
||||
"ceuciStateRank": 41,
|
||||
"stateCandidates": 687
|
||||
},
|
||||
{
|
||||
"zoneNumber": 18,
|
||||
"sollaVotes": 860,
|
||||
"ceuciVotes": 437,
|
||||
"federalValid": 47708,
|
||||
"stateValid": 46874,
|
||||
"federalComparecimento": 63580,
|
||||
"stateComparecimento": 63580,
|
||||
"sollaFederalRank": 12,
|
||||
"federalCandidates": 565,
|
||||
"ceuciStateRank": 26,
|
||||
"stateCandidates": 665
|
||||
},
|
||||
{
|
||||
"zoneNumber": 19,
|
||||
"sollaVotes": 1776,
|
||||
"ceuciVotes": 551,
|
||||
"federalValid": 82349,
|
||||
"stateValid": 78064,
|
||||
"federalComparecimento": 103825,
|
||||
"stateComparecimento": 103825,
|
||||
"sollaFederalRank": 9,
|
||||
"federalCandidates": 584,
|
||||
"ceuciStateRank": 34,
|
||||
"stateCandidates": 745
|
||||
}
|
||||
],
|
||||
"topCities": {
|
||||
"solla": [
|
||||
{
|
||||
"city_name": "Salvador",
|
||||
"votes": 27264
|
||||
},
|
||||
{
|
||||
"city_name": "Amargosa",
|
||||
"votes": 7602
|
||||
},
|
||||
{
|
||||
"city_name": "Vitória da Conquista",
|
||||
"votes": 5005
|
||||
},
|
||||
{
|
||||
"city_name": "Feira de Santana",
|
||||
"votes": 3074
|
||||
},
|
||||
{
|
||||
"city_name": "Santa Inês",
|
||||
"votes": 2925
|
||||
},
|
||||
{
|
||||
"city_name": "Mutuípe",
|
||||
"votes": 2816
|
||||
},
|
||||
{
|
||||
"city_name": "Itaberaba",
|
||||
"votes": 2558
|
||||
},
|
||||
{
|
||||
"city_name": "Governador Mangabeira",
|
||||
"votes": 2336
|
||||
}
|
||||
],
|
||||
"ceuci": [
|
||||
{
|
||||
"city_name": "Salvador",
|
||||
"votes": 19776
|
||||
},
|
||||
{
|
||||
"city_name": "Amargosa",
|
||||
"votes": 4570
|
||||
},
|
||||
{
|
||||
"city_name": "Miguel Calmon",
|
||||
"votes": 1775
|
||||
},
|
||||
{
|
||||
"city_name": "Lauro de Freitas",
|
||||
"votes": 804
|
||||
},
|
||||
{
|
||||
"city_name": "Feira de Santana",
|
||||
"votes": 552
|
||||
},
|
||||
{
|
||||
"city_name": "Itaberaba",
|
||||
"votes": 488
|
||||
},
|
||||
{
|
||||
"city_name": "Castro Alves",
|
||||
"votes": 426
|
||||
},
|
||||
{
|
||||
"city_name": "Camaçari",
|
||||
"votes": 409
|
||||
}
|
||||
]
|
||||
},
|
||||
"provenance": {
|
||||
"source": "TSE — Resultados 2022 (votação nominal por município e zona; detalhe da votação por município e zona).",
|
||||
"extractedAt": "2026-09-14",
|
||||
"extractedFrom": "Base de produção do Teqo (teqo_1313) via SELECT read-only — o CDN de dados abertos do TSE está bloqueado nesta rede.",
|
||||
"crossChecks": [
|
||||
"Solla Salvador (soma das 19 ZE) = 27.264 = soma do artefato commitado src/lib/electionAggregates/bahia-federal-baseline.json (conferida zona a zona).",
|
||||
"Ceuci estado = 36.992 = total_votes_state do registro TSE e valor noticiado na imprensa.",
|
||||
"Ceuci Salvador (soma das 19 ZE) = 19.776 = valor noticiado na imprensa (mais votada do PT na capital)."
|
||||
]
|
||||
}
|
||||
}
|
||||
1086
scripts/build-solla-ceuci-salvador-report.mjs
Normal file
1086
scripts/build-solla-ceuci-salvador-report.mjs
Normal file
File diff suppressed because it is too large
Load diff
191
scripts/lib/sollaCeuciSalvadorMetrics.mjs
Normal file
191
scripts/lib/sollaCeuciSalvadorMetrics.mjs
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
/**
|
||||
* Pure metrics for the Solla × Ceuci Salvador 2022 report (C157).
|
||||
*
|
||||
* The report compares two candidates of different offices (federal vs. state
|
||||
* deputy) inside the same geography (Salvador's 19 electoral zones). No voter
|
||||
* is observable twice — the overlap here is between two *geographies of vote*,
|
||||
* never between individual ballots — so every function works on the zone
|
||||
* vectors and the shared denominator is the zone's valid votes for each
|
||||
* office.
|
||||
*
|
||||
* Kept out of the generator script so the arithmetic is unit-testable; the
|
||||
* generator owns only I/O (geometry, HTML, PDF).
|
||||
*/
|
||||
|
||||
/** Share of a total, 0 when the denominator is missing (never NaN in the report). */
|
||||
export const shareOf = (value, total) => (total > 0 ? value / total : 0)
|
||||
|
||||
/**
|
||||
* Local quotient (LQ): the candidate's share of his own geography vote divided
|
||||
* by the geography's share of the valid votes. 1 = exactly his average; the
|
||||
* report's "above/below own average" line.
|
||||
*/
|
||||
export const localQuotient = (value, ownTotal, valid, validTotal) => {
|
||||
const ownShare = shareOf(value, ownTotal)
|
||||
const validShare = shareOf(valid, validTotal)
|
||||
return validShare > 0 ? ownShare / validShare : 0
|
||||
}
|
||||
|
||||
/** Pearson correlation; returns 0 for degenerate vectors (n < 2 or no variance). */
|
||||
export const pearson = (xs, ys) => {
|
||||
const n = Math.min(xs.length, ys.length)
|
||||
if (n < 2) return 0
|
||||
const meanX = xs.reduce((sum, value) => sum + value, 0) / n
|
||||
const meanY = ys.reduce((sum, value) => sum + value, 0) / n
|
||||
let covariance = 0
|
||||
let varianceX = 0
|
||||
let varianceY = 0
|
||||
for (let index = 0; index < n; index += 1) {
|
||||
const dx = xs[index] - meanX
|
||||
const dy = ys[index] - meanY
|
||||
covariance += dx * dy
|
||||
varianceX += dx * dx
|
||||
varianceY += dy * dy
|
||||
}
|
||||
if (varianceX === 0 || varianceY === 0) return 0
|
||||
return covariance / Math.sqrt(varianceX * varianceY)
|
||||
}
|
||||
|
||||
/** Competition ranks with ties averaged — the honest rank for Spearman. */
|
||||
export const averageRanks = (values) => {
|
||||
const order = values
|
||||
.map((value, index) => [value, index])
|
||||
.sort((left, right) => left[0] - right[0])
|
||||
const ranks = new Array(values.length).fill(0)
|
||||
let start = 0
|
||||
while (start < order.length) {
|
||||
let end = start
|
||||
while (end + 1 < order.length && order[end + 1][0] === order[start][0]) end += 1
|
||||
const rank = (start + end) / 2 + 1
|
||||
for (let index = start; index <= end; index += 1) ranks[order[index][1]] = rank
|
||||
start = end + 1
|
||||
}
|
||||
return ranks
|
||||
}
|
||||
|
||||
/** Spearman rank correlation (Pearson over average ranks). */
|
||||
export const spearman = (xs, ys) => pearson(averageRanks(xs), averageRanks(ys))
|
||||
|
||||
/**
|
||||
* Overlap coefficient between two share vectors: Σ min(aᵢ, bᵢ). 1 = identical
|
||||
* distributions, 0 = disjoint. Scale-free (both vectors sum to ~1), which is
|
||||
* what makes a federal candidate comparable with a state one.
|
||||
*/
|
||||
export const overlapCoefficient = (a, b) => {
|
||||
const n = Math.min(a.length, b.length)
|
||||
let total = 0
|
||||
for (let index = 0; index < n; index += 1) total += Math.min(a[index], b[index])
|
||||
return total
|
||||
}
|
||||
|
||||
/** Cosine similarity between two vectors (scale-invariant). */
|
||||
export const cosineSimilarity = (a, b) => {
|
||||
const n = Math.min(a.length, b.length)
|
||||
let dot = 0
|
||||
let normA = 0
|
||||
let normB = 0
|
||||
for (let index = 0; index < n; index += 1) {
|
||||
dot += a[index] * b[index]
|
||||
normA += a[index] * a[index]
|
||||
normB += b[index] * b[index]
|
||||
}
|
||||
if (normA === 0 || normB === 0) return 0
|
||||
return dot / Math.sqrt(normA * normB)
|
||||
}
|
||||
|
||||
/** Herfindahl–Hirschman index over shares (concentration; 1/19 ≈ uniform). */
|
||||
export const hhi = (shares) => shares.reduce((sum, value) => sum + value * value, 0)
|
||||
|
||||
/** Sum of the `n` largest shares — the "top-3 zones" concentration reading. */
|
||||
export const topShare = (shares, n) =>
|
||||
[...shares]
|
||||
.sort((left, right) => right - left)
|
||||
.slice(0, n)
|
||||
.reduce((sum, value) => sum + value, 0)
|
||||
|
||||
export const ZONE_CLASSES = {
|
||||
shared: {
|
||||
key: 'shared',
|
||||
label: 'Reduto compartilhado',
|
||||
short: 'Ambos acima da média',
|
||||
color: '#c51414',
|
||||
},
|
||||
solla: { key: 'solla', label: 'Base Solla', short: 'Só Solla acima da média', color: '#1e40af' },
|
||||
ceuci: { key: 'ceuci', label: 'Ponte Ceuci', short: 'Só Ceuci acima da média', color: '#0d9488' },
|
||||
open: { key: 'open', label: 'Disputa ampla', short: 'Ambos abaixo da média', color: '#d4d4d8' },
|
||||
}
|
||||
|
||||
/** Crosses the two LQs into the report's four operational classes. */
|
||||
export const classifyZone = (sollaLq, ceuciLq) => {
|
||||
if (sollaLq >= 1 && ceuciLq >= 1) return ZONE_CLASSES.shared
|
||||
if (sollaLq >= 1) return ZONE_CLASSES.solla
|
||||
if (ceuciLq >= 1) return ZONE_CLASSES.ceuci
|
||||
return ZONE_CLASSES.open
|
||||
}
|
||||
|
||||
/** Per-zone table rows, sorted by zone number (the printed order). */
|
||||
export const buildZoneMetrics = ({ zones, salvadorTotals }) =>
|
||||
zones.map((zone) => {
|
||||
const sollaShareOwn = shareOf(zone.sollaVotes, salvadorTotals.sollaVotes)
|
||||
const ceuciShareOwn = shareOf(zone.ceuciVotes, salvadorTotals.ceuciVotes)
|
||||
const sollaLq = localQuotient(
|
||||
zone.sollaVotes,
|
||||
salvadorTotals.sollaVotes,
|
||||
zone.federalValid,
|
||||
salvadorTotals.federalValid,
|
||||
)
|
||||
const ceuciLq = localQuotient(
|
||||
zone.ceuciVotes,
|
||||
salvadorTotals.ceuciVotes,
|
||||
zone.stateValid,
|
||||
salvadorTotals.stateValid,
|
||||
)
|
||||
return {
|
||||
...zone,
|
||||
sollaShareOwn,
|
||||
ceuciShareOwn,
|
||||
sollaShareValid: shareOf(zone.sollaVotes, zone.federalValid),
|
||||
ceuciShareValid: shareOf(zone.ceuciVotes, zone.stateValid),
|
||||
sollaLq,
|
||||
ceuciLq,
|
||||
overlapMin: Math.min(sollaShareOwn, ceuciShareOwn),
|
||||
combinedVotes: zone.sollaVotes + zone.ceuciVotes,
|
||||
sollaLeads: zone.sollaVotes > zone.ceuciVotes,
|
||||
zoneClass: classifyZone(sollaLq, ceuciLq),
|
||||
}
|
||||
})
|
||||
|
||||
/** Summary readings printed in the executive summary and the method annex. */
|
||||
export const buildReportSummary = ({ metrics, candidates, salvadorTotals }) => {
|
||||
const sollaShares = metrics.map((zone) => zone.sollaShareOwn)
|
||||
const ceuciShares = metrics.map((zone) => zone.ceuciShareOwn)
|
||||
const sollaVotes = metrics.map((zone) => zone.sollaVotes)
|
||||
const ceuciVotes = metrics.map((zone) => zone.ceuciVotes)
|
||||
|
||||
const byClass = (key) => metrics.filter((zone) => zone.zoneClass.key === key)
|
||||
const strongestCeuci = [...metrics].sort((left, right) => right.ceuciVotes - left.ceuciVotes)
|
||||
const strongestCombined = [...metrics].sort(
|
||||
(left, right) => right.combinedVotes - left.combinedVotes,
|
||||
)
|
||||
const ceuciAhead = metrics.filter((zone) => zone.ceuciVotes > zone.sollaVotes)
|
||||
|
||||
return {
|
||||
overlapCoefficient: overlapCoefficient(sollaShares, ceuciShares),
|
||||
cosine: cosineSimilarity(sollaShares, ceuciShares),
|
||||
pearson: pearson(sollaVotes, ceuciVotes),
|
||||
spearman: spearman(sollaVotes, ceuciVotes),
|
||||
sollaTop3Share: topShare(sollaShares, 3),
|
||||
ceuciTop3Share: topShare(ceuciShares, 3),
|
||||
sollaHhi: hhi(sollaShares),
|
||||
ceuciHhi: hhi(ceuciShares),
|
||||
salvadorShareOfSollaState: shareOf(salvadorTotals.sollaVotes, candidates.solla.stateVotes),
|
||||
salvadorShareOfCeuciState: shareOf(salvadorTotals.ceuciVotes, candidates.ceuci.stateVotes),
|
||||
shared: byClass('shared'),
|
||||
sollaOnly: byClass('solla'),
|
||||
ceuciOnly: byClass('ceuci'),
|
||||
open: byClass('open'),
|
||||
strongestCeuci,
|
||||
strongestCombined,
|
||||
ceuciAhead,
|
||||
}
|
||||
}
|
||||
112
tests/unit/sollaCeuciSalvadorMetrics.unit.spec.ts
Normal file
112
tests/unit/sollaCeuciSalvadorMetrics.unit.spec.ts
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import {
|
||||
averageRanks,
|
||||
buildReportSummary,
|
||||
buildZoneMetrics,
|
||||
classifyZone,
|
||||
cosineSimilarity,
|
||||
hhi,
|
||||
localQuotient,
|
||||
overlapCoefficient,
|
||||
pearson,
|
||||
shareOf,
|
||||
spearman,
|
||||
topShare,
|
||||
ZONE_CLASSES,
|
||||
} from '../../scripts/lib/sollaCeuciSalvadorMetrics.mjs'
|
||||
|
||||
describe('sollaCeuciSalvadorMetrics', () => {
|
||||
it('keeps shareOf safe on a missing denominator', () => {
|
||||
expect(shareOf(10, 40)).toBe(0.25)
|
||||
expect(shareOf(10, 0)).toBe(0)
|
||||
})
|
||||
|
||||
it('computes the local quotient against the valid-vote share', () => {
|
||||
// 10% of the candidate's vote in a zone holding 5% of the valid votes → LQ 2.
|
||||
expect(localQuotient(10, 100, 50, 1000)).toBeCloseTo(2)
|
||||
// Zone with no valid votes never divides by zero.
|
||||
expect(localQuotient(10, 100, 0, 1000)).toBe(0)
|
||||
})
|
||||
|
||||
it('computes Pearson on a perfectly correlated pair', () => {
|
||||
expect(pearson([1, 2, 3], [2, 4, 6])).toBeCloseTo(1)
|
||||
expect(pearson([1, 2, 3], [6, 4, 2])).toBeCloseTo(-1)
|
||||
expect(pearson([1], [2])).toBe(0)
|
||||
expect(pearson([1, 1, 1], [1, 2, 3])).toBe(0)
|
||||
})
|
||||
|
||||
it('averages tied ranks and correlates ranks for Spearman', () => {
|
||||
expect(averageRanks([10, 20, 20, 30])).toEqual([1, 2.5, 2.5, 4])
|
||||
expect(spearman([1, 2, 3], [10, 20, 30])).toBeCloseTo(1)
|
||||
})
|
||||
|
||||
it('measures distribution overlap and cosine similarity', () => {
|
||||
expect(overlapCoefficient([0.5, 0.5], [0.5, 0.5])).toBeCloseTo(1)
|
||||
expect(overlapCoefficient([1, 0], [0, 1])).toBe(0)
|
||||
expect(cosineSimilarity([1, 0], [1, 0])).toBeCloseTo(1)
|
||||
expect(cosineSimilarity([0, 0], [1, 0])).toBe(0)
|
||||
})
|
||||
|
||||
it('measures concentration with HHI and top shares', () => {
|
||||
expect(hhi([0.5, 0.5])).toBeCloseTo(0.5)
|
||||
expect(topShare([0.1, 0.4, 0.3, 0.2], 2)).toBeCloseTo(0.7)
|
||||
})
|
||||
|
||||
it('classifies the four LQ quadrants', () => {
|
||||
expect(classifyZone(1.2, 1.1)).toBe(ZONE_CLASSES.shared)
|
||||
expect(classifyZone(1.2, 0.9)).toBe(ZONE_CLASSES.solla)
|
||||
expect(classifyZone(0.9, 1.2)).toBe(ZONE_CLASSES.ceuci)
|
||||
expect(classifyZone(0.9, 0.9)).toBe(ZONE_CLASSES.open)
|
||||
})
|
||||
|
||||
it('builds per-zone metrics and the summary from a two-zone fixture', () => {
|
||||
const zones = [
|
||||
{
|
||||
zoneNumber: 1,
|
||||
sollaVotes: 80,
|
||||
ceuciVotes: 20,
|
||||
federalValid: 800,
|
||||
stateValid: 800,
|
||||
sollaFederalRank: 1,
|
||||
federalCandidates: 10,
|
||||
ceuciStateRank: 9,
|
||||
stateCandidates: 10,
|
||||
},
|
||||
{
|
||||
zoneNumber: 2,
|
||||
sollaVotes: 20,
|
||||
ceuciVotes: 80,
|
||||
federalValid: 500,
|
||||
stateValid: 200,
|
||||
sollaFederalRank: 9,
|
||||
federalCandidates: 10,
|
||||
ceuciStateRank: 1,
|
||||
stateCandidates: 10,
|
||||
},
|
||||
]
|
||||
const salvadorTotals = {
|
||||
sollaVotes: 100,
|
||||
ceuciVotes: 100,
|
||||
federalValid: 1000,
|
||||
stateValid: 1000,
|
||||
}
|
||||
const metrics = buildZoneMetrics({ zones, salvadorTotals })
|
||||
// Zone 1: 80% of Solla's vote over 80% of the valid votes → LQ 1; Ceuci 0.2/0.8 → 0.25.
|
||||
expect(metrics[0].sollaLq).toBeCloseTo(1)
|
||||
expect(metrics[0].ceuciLq).toBeCloseTo(0.25)
|
||||
expect(metrics[0].zoneClass).toBe(ZONE_CLASSES.solla)
|
||||
expect(metrics[1].zoneClass).toBe(ZONE_CLASSES.ceuci)
|
||||
|
||||
const summary = buildReportSummary({
|
||||
metrics,
|
||||
candidates: { solla: { stateVotes: 200 }, ceuci: { stateVotes: 400 } },
|
||||
salvadorTotals,
|
||||
})
|
||||
expect(summary.overlapCoefficient).toBeCloseTo(0.4)
|
||||
expect(summary.pearson).toBeCloseTo(-1)
|
||||
expect(summary.salvadorShareOfSollaState).toBeCloseTo(0.5)
|
||||
expect(summary.salvadorShareOfCeuciState).toBeCloseTo(0.25)
|
||||
expect(summary.ceuciAhead.map((zone: { zoneNumber: number }) => zone.zoneNumber)).toEqual([2])
|
||||
})
|
||||
})
|
||||
Loading…
Reference in a new issue