Versões
Todas as mudanças importantes do projeto, em ordem reversa cronológica. Formato segue Keep a Changelog; versões em SemVer.
Histórico de versões
Registro cronológico de tudo que mudou no painel — dados, metodologia e interface —, da versão mais recente para a mais antiga.
Página 10 de 14 · 167 versões no total.
-
v4.11.1 2026-07-24 Painel muito mais rápido Fixed
- Páginas que demoravam segundos agora abrem instantaneamente. O Cenário Geral levava cerca de 6 segundos em toda visita (não só na primeira), e o Comparativo chegava a quase um minuto depois de cada coleta. Agora as páginas do painel respondem em frações de segundo — na prática, a navegação deixa de ter espera perceptível.
- Fim da lentidão logo após cada atualização de dados. O painel guarda os resultados prontos em memória para não repetir o mesmo trabalho a cada visita, e essa memória é naturalmente descartada quando entram dados novos (3× por dia). Quem visitasse primeiro pagava a conta. Agora o próprio processo de coleta já deixa as páginas preparadas ao terminar, então esse custo não recai mais sobre quem acessa.
- A Home não depende mais do blog para carregar. A lista de análises publicadas era buscada no site a cada visita, o que somava tempo e travava a página quando o blog estava lento. Passa a ser atualizada junto com os dados do painel.
Notes
- Medições na LXC (acesso público, via Cloudflare): Cenário Geral 6,3s → 0,38s; Comparativo até 58s → 0,48s; Pré-candidatos 2,3s → 0,30s; Espectro 2,4s → 0,39s; Home 1,1s → 0,39s.
- As melhorias são de infraestrutura: nenhum número, gráfico ou critério de análise mudou.
-
v4.11.0 2026-07-20 Renan Santos: primeiro candidato oficializado Changed
- Renan Santos (Missão) promovido de
pre-candidateparacandidate— oficializado em convenção partidária (formato online, antecipada por razões de segurança) em 20/07/2026, tornando-se o primeiro candidato à Presidência com candidatura homologada da corrida de 2026. Empresário e ativista, fundador do Movimento Brasil Livre (MBL) em 2014. Anunciou chapa "puro-sangue" (candidato e vice do mesmo partido); lançamento oficial da campanha marcado para 01/08/2026. Fontes: O Tempo, Correio Braziliense e Gazeta do Povo, 20/07/2026.status_changed_at= 20/07/2026. Registros históricos preservados; segue aparecendo em todos os grids (o filtro de dados éstatus != 'dropped').
Added
- Selo "Candidato" nas páginas de pré-candidatos — o grid
/pre-candidatospassa a exibir um badge verde "Candidato" nos cards de quem já teve a candidatura oficializada, e a página individual troca o rótulo do cabeçalho dePAINEL · PRÉ-CANDIDATOparaPAINEL · CANDIDATO. A Metodologia já distinguia os três status (Pré-candidato / Candidato / Descontinuado). Preparação para o período de convenções (agosto), quando mais nomes migram de pré-candidato para candidato.
- Renan Santos (Missão) promovido de
-
v4.10.1 2026-07-10 Aécio Neves dropped Changed
- Aécio Neves (PSDB) marcado como
status='dropped'no banco — desistiu da pré-candidatura à Presidência em 09/07/2026, citando isolamento e ausência de alianças ("Não vou fazer uma travessia solitária"). A pré-candidatura havia sido aprovada pela federação PSDB/Cidadania/Solidariedade em convenção de junho; o PSDB não lançará candidato próprio e tende à neutralidade entre Lula e Flávio Bolsonaro, mirando projeto de terceira via em 2030. Fontes: g1 e O Globo, 09/07/2026. Status alterado em 10/07/2026 (status_changed_atretroativo à data do anúncio). - Coletores (Brave/Google News/Tavily) passam a ignorar Aécio automaticamente a partir da coleta das 14h de 10/07 (registros históricos preservados no banco).
- README atualizado: Aécio movido para "Descontinuados"; lista de candidatos sincronizada com o estado real do banco (Ciro Gomes constava como ativo desde o drop de 09/05; Michelle Bolsonaro constava como descontinuada apesar da reativação de 13/05; Edmilson Costa e Joaquim Barbosa não constavam).
- 📝 Metodologia: 14 pré-candidatos ativos + 5 dropped (Aécio Neves, Ciro Gomes, Eduardo Leite, Leonardo Péricles, Tarcísio de Freitas).
- Aécio Neves (PSDB) marcado como
-
v4.10.0 2026-07-07 Alinhamento ao Design System (DS 1.6.0) Fixed
- Tipografia dos títulos restaurada — os valores em destaque (KPIs, nomes de card) referenciavam um token de fonte inexistente e caíam em Archivo Narrow em vez de Antonio. Agora os números grandes voltam à fonte editorial condensada correta.
- Números e datas em formato brasileiro — placares de sentimento e percentuais que apareciam com ponto decimal (
+0.35,12.3%) passam a usar vírgula (+0,35,12,3%); contagens grandes usam ponto de milhar de forma consistente. - Linha "Total" da timeline visível no tema escuro — era desenhada na mesma cor do fundo e sumia; agora usa um cinza neutro legível nos dois temas.
Changed
- Cores unificadas com a frota SapiensLabs — o espectro editorial e as cores de sentimento passam a vir dos tokens compartilhados do Design System (mesma paleta dos monitores da Câmara e do Senado), com variantes de contraste próprias para o tema claro. O azul de marca deixa de ser reaproveitado como cor de "direita".
- Gráficos na camada Plotly canônica — fonte Archivo Narrow, separadores numéricos brasileiros e paletas alinhadas ao DS; os gráficos passam a acompanhar a troca de tema claro/escuro.
Notes
- Página de Privacidade ajustada para descrever o comportamento real do tema (segue o sistema operacional e o horário; nada é gravado no navegador por conta do painel).
-
v4.9.0 2026-06-30 Consistência de contagem e endpoints de agregação Fixed
- Janela temporal unificada com
DATE()—published_até ISO comTe timezone (2026-06-07T14:00+00:00); comparar a borda superior por string (<= to) excluía o dia final inteiro porque'T'(0x54) >' '(0x20)./api/v1/articlese a busca de artigos relacionados passam a usarDATE(published_at), incluindo o dia final. Antes,/articlesretornava menos artigos que a série de sentimento para a mesma janela (ex.: Lula 01–07/06: 1378 vs 1478 — os 100 artigos do dia 07). - Série de sentimento respeita
from/to—/api/v1/candidates/{slug}/sentimentaceitava os parâmetros mas os ignorava (devolvia sempre a série desde 25/03). Agora filtra a janela comDATE(). - Tópicos do Comparativo filtram menção verificada — as agregações de tópicos em
/comparativo(grafo bipartite + colunas por candidato) contavam tópicos de artigos não-verificados, divergindo do resto do dashboard. Agora exigemarticle_candidates.verified = 1.
Added
GET /api/v1/candidates/{slug}/topics— top tópicos sobre um candidato na janela (from,to,limit), artigos únicos verificados.GET /api/v1/candidates/{slug}/sources— top veículos sobre um candidato na janela. Tornam verificáveis publicamente as afirmações dos resumos sobre tópicos e fontes por período.
Notes
- Métrica oficial de volume: artigo único (
COUNT(DISTINCT a.id)) comverified = 1, janela porDATE(published_at). Os produtores de resumo (semanal/mensal, no projetoblog-automation) foram alinhados a essa métrica — antes contavam pares (COUNT(*)) semverified, o que inflava os números publicados frente à API que citam como fonte.
- Janela temporal unificada com
-
v4.8.1 2026-05-22 Aécio Neves (Cidadania) Added
- 🗳️ Novo pré-candidato: Aécio Neves (Cidadania) — Ex-governador de Minas Gerais (2003-2010, PSDB), ex-senador, deputado federal pela quinta vez (eleito em 2022). Candidato à Presidência em 2014 pelo PSDB, perdeu o segundo turno para Dilma Rousseff. Migrou para o Cidadania, que aprovou sua pré-candidatura à Presidência em reunião da Executiva Nacional em 22/05/2026. Coleta dedicada começa na próxima rodada do pipeline. Patterns + queries (Brave, Tavily, Google News) adicionados em
src/candidate_utils.pyesrc/coletores/google_news.py.
- 🗳️ Novo pré-candidato: Aécio Neves (Cidadania) — Ex-governador de Minas Gerais (2003-2010, PSDB), ex-senador, deputado federal pela quinta vez (eleito em 2022). Candidato à Presidência em 2014 pelo PSDB, perdeu o segundo turno para Dilma Rousseff. Migrou para o Cidadania, que aprovou sua pré-candidatura à Presidência em reunião da Executiva Nacional em 22/05/2026. Coleta dedicada começa na próxima rodada do pipeline. Patterns + queries (Brave, Tavily, Google News) adicionados em
-
v4.8.0 2026-05-17 Fonte mais quente da semana + categoria Agregador Duas mudanças que se sustentam mutuamente. O card "KPI da Semana" na Home ganha uma quarta linha noticiosa — qual veículo publicou mais sobre a eleição na janela; e a taxonomia editorial ganha uma sexta categoria, Agregador, pra distinguir fontes não-redacionais das redações com linha editorial humana.
Added
- 🏷️ Card "Fonte mais quente" na Home — quarta estatística do bloco semanal, mostrando o veículo com maior volume na janela atual (segunda a domingo) e variação vs. semana anterior. Filtra explicitamente para fontes editorialmente classificadas (
editorial_lean_detail IN (extrema-esquerda, esquerda, centro, direita, extrema-direita)); agregadores e fontes não mapeadas ficam fora do ranking por desenho. Backend:_top_source_for_window()emdata.py, integrado ao retorno decenario_semanal_kpis(). - 🆕 Categoria editorial "Agregador" (
agregadordetail /aggregatorbroad) — nova dimensão paralela ao eixo esquerda↔direita, descrevendo a natureza da fonte (não-redacional, reescrita automatizada / IA, sem linha editorial humana atribuível). Critérios objetivos documentados emCLASSIFICACAO.md: sem expediente, sem bylines, volume incompatível com redação humana, maioria das matérias sem atribuição, indicadores linguísticos de LLM sem disclosure. Primeira fonte classificada: Notícias do Brasil (noticias-do-brasil.news).
Changed
- 🔁
noticias-do-brasilrecategorizado — antes classificado comocenter/centro(default arbitrário do cadastro RSS), agora marcado comoaggregator/agregador. Aplicado retroativamente a 1280 artigos no banco (privado + público) e à entrada do feed emconfig/rss_feeds.jsonpra próximas coletas. Fonte continua sendo coletada — só sai das KPIs editoriais. - 🔧
source_lean_map.py:DETAIL_TO_BROADganha entradaagregador → aggregator; nova seção "AGREGADOR" noSOURCE_LEAN_MAP_DETAILcom as variantes de nome/host de Notícias do Brasil. - 🔧
refresh_editorial_lean_detail.py:BROAD_TO_DETAIL_FALLBACKganhaaggregator → agregador.
Notes
- Por que o critério "Agregador" descreve natureza, não alinhamento. As 5 categorias do eixo editorial (extrema-esquerda → extrema-direita) pressupõem decisão humana de linha. Aplicar uma delas a um site que reescreve via LLM matérias de terceiros era um erro categorial: rotulava como "centro" qualquer agregador que cobrisse o noticiário consensual sem viés panfletário. A categoria nova é o vocabulário que faltava.
- Critérios formais do eixo esquerda↔direita continuam como pendência aberta. Esta versão adiciona uma 6ª categoria, mas não revisa as 5 originais. O fato de o
rss_feeds.jsonter camposleanatribuídos manualmente sem documentação é o sintoma mais visível dessa dívida.
- 🏷️ Card "Fonte mais quente" na Home — quarta estatística do bloco semanal, mostrando o veículo com maior volume na janela atual (segunda a domingo) e variação vs. semana anterior. Filtra explicitamente para fontes editorialmente classificadas (
-
v4.7.0 2026-05-16 Ficha por matéria + Joaquim Barbosa (DC) Duas adições estruturais. Cada link de matéria nas listas do dashboard agora abre uma ficha analítica interna que mostra tudo que o banco tem sobre ela; e Joaquim Barbosa entra como pré-candidato do Democracia Cristã, em movimento que disputa internamente com a pré-candidatura de Aldo Rebelo no mesmo partido.
Added
- 📰
/cobertura/{id}/{slug}— ficha analítica por matéria. Cada link de matéria nas listas (Cobertura mais recente, Artigos da semana/mês, listagem na página de pré-candidato) passa a abrir uma página interna com alinhamento editorial do veículo, gênero jornalístico, cluster Zeitgeist, tópicos identificados, sentimento por pré-candidato (tabela) e até 5 matérias relacionadas (janela ±3 dias, score por mesmo cluster + co-ocorrência de candidatos). CTA proeminente "Ler matéria completa em [veículo]" no topo e<link rel="canonical" href="{url_original}">no head pra respeitar a fonte. Open Graph completo pra compartilhamento. Backend:data.article_detail(id)+ slugify NFKD ASCII (kebab, max 60 chars cortado na palavra). - 🗳️ Novo pré-candidato: Joaquim Barbosa (DC) — Ex-ministro do STF (2003–2014), primeiro negro a presidir o Supremo. Relator da AP 470 (Caso Mensalão). Aposentou-se voluntariamente em 2014. Filiou-se ao Democracia Cristã em maio/2026; cotado pelo partido como nome para disputar a Presidência em 2026, em movimento que se sobrepõe à pré-candidatura de Aldo Rebelo lançada pelo mesmo DC em 07/05/2026 (disputa interna documentada por Carta Capital, Poder360, Revista Fórum e DCM). Coleta dedicada começou na rodada das 21:00 BRT de 16/05.
- 🔍 10 artigos retroativos sobre JB que já estavam no banco (coletados por menção cruzada em queries do Aldo) foram associados ao novo candidato e classificados pelo
sentimento.py(10/10positive— tom favorável da cobertura sobre a filiação ao DC). Tópicos e Zeitgeist já estavam preenchidos.
Changed
- 🔄 Listas de artigos refatoradas pra usar partial reutilizável (
partials/article_list_item.html) — 9 blocos duplicados em 5 templates consolidados em 1 só. Listas passam a linkar pra ficha interna (internal_url) em vez de direto pro veículo; link original preservado dentro da ficha. - 📊 5 funções de listagem em
data.pyretornamid+internal_url—recent_articles,_articles_for_window(semanal/mensal),candidate_detail.articles,emerging_topics.examples. Esquema consistente: toda lista de matérias do banco entra na navegação interna. - 📝 Metodologia ganhou seção dedicada à ficha por matéria.
Notes
- Lacuna nas queries dos coletores corrigida no mesmo dia — descobriu-se que adicionar um pré-candidato exige 5 mudanças (INSERT em
candidates+ patterns emCANDIDATE_PATTERNS+ queries emBRAVE_QUERIES/TAVILY_QUERIES/GNEWS_QUERIES), não só o INSERT. Comentário inline emsrc/candidate_utils.pyjá documentava isso desde sempre. Procedimento agora rodado integralmente pro JB; checklist registrado em memória curada. rel=canonicaldas fichas aponta pra fonte original — decisão editorial de respeito ao trabalho dos veículos cobertos. O painel não disputa SEO da palavra-chave; a ficha agrega valor analítico próprio.
- 📰
-
v4.6.1 2026-05-12 Migração Gemini 3.1 Flash Lite para GA Changed
gemini_client.py: model ID atualizado degemini-3.1-flash-lite-previewparagemini-3.1-flash-lite(GA). Mesmo modelo, só o identificador mudou — sem alteração de comportamento nem de custos. Preview descontinuado pelo Google em 25/05/2026.
-
v4.6.0 2026-05-10 Edmilson Costa (PCB) entra no monitoramento Adição tardia de pré-candidato presidencial: Edmilson Costa, lançado pelo Comitê Central do PCB em 24/02/2026 com slogan "Por um governo do Poder Popular". A imprensa já vinha tratando-o como pré-candidato em listas de pesquisa eleitoral (Meio/Ideia, Real Time Big Data) — a inclusão regulariza o registro no painel.
Added
- 🗳️ Novo pré-candidato: Edmilson Costa (PCB) — Doutor em Economia pela Unicamp, com pós-doutorado no IFCH/Unicamp. Militante histórico do PCB, perseguido na ditadura militar como líder estudantil.
- 🔍 Busca retroativa: 11 artigos existentes vinculados ao novo candidato na tabela
article_candidates(todos como menção em listas de pesquisa eleitoral; nenhum dedicado). - ⚙️ Coleta futura configurada: 3 patterns regex, 5 queries Brave e 3 Tavily em
candidate_utils.py. Patterns conservadores (sem\bcosta\bsolto — sobrenome muito comum).
Changed
- 📝 Metodologia: 12 pré-candidatos ativos (era 11) + 5 dropped (Ciro Gomes, Eduardo Leite, Leonardo Péricles, Michelle Bolsonaro, Tarcísio de Freitas).
-
v4.5.0 2026-05-10 Bundle Plotly custom (1.2MB vs 4.6MB) Bundle Plotly trocado do full distribution (4.6MB) para bundle custom (1.2MB, -73%) com apenas os 5 trace types que o dashboard de fato usa: Bar, Heatmap, Scatter, Scatterpolar, Treemap. Constructed via esbuild sob
frontend/.Added
frontend/— toolchain JS isolada do projeto Python:package.json— declaraplotly.js@3.0.1+esbuild@^0.24.0como devDepsplotly-bundle.js— entry point que importaplotly.js/lib/core+ traces individuais viaPlotly.register([Bar, Heatmap, Scatter, Scatterpolar, Treemap])global-shim.js— shim ESM injetado no bundle pra polyfillarglobalThis.global(fallback se runtime shim falhar)npm run build→ esbuild geraapp/static/js/plotly-custom-3.0.1.min.js
- Runtime shim em
base.html—<script>window.global = window;</script>ANTES do bundle. Plotly v3 tem código que referencia bareglobaldentro do IIFE, fora do alcance do--define/--banner/--injectdo esbuild. O shim no escopowindowresolve qualquerglobalvia scope chain. 1-linha, robusto, dispensa re-build a cada mudança.
Changed
base.html— referência muda deplotly-3.0.1.min.js(4.6MB) praplotly-custom-3.0.1.min.js(1.2MB).app/static/js/plotly-3.0.1.min.jsremovido do repo (não é mais usado).
Notes
- Validação no Chrome: 6 traces em
/comparativo(bar + scatter), 1 em/radar(scatterpolar), 4 em/cenario-geral(scatter + heatmap + treemap). Zero erros console. - Manutenção pós-upgrade Plotly: bumpar versão em
frontend/package.json,cd frontend && npm install && npm run build, atualizar nome do arquivo embase.html(carrega versão no nome pra cache-bust). Documentado emfrontend/plotly-bundle.js. - Tentativas falhadas antes do shim runtime:
--define:global=globalThis(substituição textual não pegou todos os usos),--banner:js="var global=..."(sombreado pela IIFE),--inject:./global-shim.js(módulo importado mas escopo isolado). Conselho do advisor: shim nowindowantes do script é mais simples e robusto.
Performance
- Tamanho bruto: 4.6MB → 1.2MB (-73%)
- First-visit em 4G médio (5Mbps efetivo): ~7.5s → ~2s (economia ~5.5s)
- First-visit em 100Mbps: ~370ms → ~100ms (economia ~270ms)
- Subsequent visits: zero (browser cache + CF cache 4h em ambos os casos)
-
v4.4.0 2026-05-10 HTMX em filter changes (4 rotas) Filter changes em
/comparativo,/radar,/espectroe/cenario-geraldeixam de fazer full page reload e passam a fazer fragment swap via HTMX. Form ganha auto-trigger nochange(debounce 300ms) — não precisa mais clicar "Atualizar". Classe ativa das pills do/cenario-geralé re-renderizada junto com o partial.Added
- HTMX 2.0.4 self-host em
app/static/js/htmx-2.0.4.min.js(51KB, mesmo motivo do Plotly: evita DNS/TLS pra CDN, reaproveita HTTP/2 do mesmo domínio). - Listener global em
base.htmlque re-executa<script>inline injetado por swap. Browsers não executam scripts que entram viainnerHTML— o listener detectahtmx:afterSwape re-cria cada<script>como nó novo (browser executa nós recém-injetados). Chave para fazer Plotly funcionar pós-swap (pio.to_html()injeta<div>+<script>Plotly.newPlot()</script>inline). - Partials por rota em
app/templates/partials/:comparativo_results.html— tabela resumo + 7 charts + top tópicosradar_results.html— spider chart + tabela de valores brutosespectro_results.html— KPIs por espectro + 4 chartscenario_geral_results.html— pills + KPIs + 5 charts + lista de artigos
- Detecção de
HX-Requestheader nas 4 rotas — se presente, retornapartials/<rota>_results.html; se ausente, retornapages/<rota>.htmlque{% include %}o partial. Sem duplicação de lógica de contexto. Compatível com no-JS (forms ainda submetem normalmente).
Changed
- Forms ganham
hx-trigger="change delay:300ms"— qualquer toggle de checkbox dispara filter change após 300ms de inatividade (debounce). Botão "Atualizar" mantido como fallback. - Pills do
/cenario-geralganhamhx-get+hx-target+hx-push-url— funcionam tanto como links normais (no-JS) quanto como swap HTMX. hx-push-url="true"em todas as rotas — URL no browser atualiza junto com o swap, mantém comportamento de navegação esperado (back button, share URL, etc.).
Notes
- Ganho de tempo no filter change varia conforme cache do
db_cached:- Cache hit (rota leve, ex.:
/cenario-geral?period=30dsegunda vez): ~700-1000ms full reload → ~150-300ms swap. Redução ~80%. - Cache miss (rota cara, ex.:
/comparativocom seleção nova): ~8-15s full reload → ~8-15s swap (mesma carga server-side; ganho marginal de render+transfer). Mas a sensação de "responsividade" do click é melhor — UI muda instantaneamente quando a resposta chega, sem flash de white reload.
- Cache hit (rota leve, ex.:
- Todas as outras rotas (
/,/zeitgeist,/cenario-mensal,/cenario-semanal,/pre-candidatos,/pre-candidatos/{slug},/analises,/metodologia,/changelog,/privacidade) ficam intocadas — não têm filtros interativos e portanto não precisam de HTMX.
- HTMX 2.0.4 self-host em