Cross-checked by parallel code-quality/performance/reuse reviewers against
the E9 commit. Behavior-preserving:
- laterTimestamp/resolveMunicipalityLastSignalAt were the same "latest of
two ISO timestamps" written twice; both now delegate to a new
latestIsoTimestamp in campaignTime.ts, which documents the fixed-width
UTC invariant that makes the string compare sound.
- Hoisted the frescor comparator's Date.now() out of the per-comparison
accessor so the sort key stops drifting mid-sort.
- Deleted the unread baseTotal/growthFactor/belowBase passthrough from the
statewide goal entry point and fixed a comment citing a symbol
(goalDecompositionBelowBase) that never existed; renamed
computeStatewideGoalDecomposition -> computeStatewideSuggestedGoals now
that nothing is proportionally decomposed.
- Collapsed the advisor badge's two copies (desktop table vs mobile card)
into one AdvisorStatusBadge; they had quietly diverged on which icon
renders for the "no advisor" state.
- Renamed the sort-menu's stale "Cobertura" label for advisor coverage to
"Assessoria" (E8 already renamed the list column for the same reason);
derived the sort-key set from the label record instead of a third
parallel list.
- Consolidated three zeroed-scenario-record literals into one
zeroByVoteEstimateScenario() factory in voteEstimate.ts.
- Routed three separate votesByYear[2022] reads through one votesInYear
helper in municipalityPotential.ts.
- Gated the goal card's empty-state copy on !usesMesaEstimate so it stops
telling a município with an existing mesa estimate to enter one.
- Swapped a test assertion pinned to a raw Tailwind token for a stable
data-signal="cold" hook, and tightened the "desert" test's bound to
check against the actual growth factor (the old bound was true for
every slug regardless of the formula).
Left alone (roadmap decision, not cleanup): sanityCheckSuggestedGoalsByTerritory
has no production caller yet (deferred to E11/E12); comment shortened
instead of deleting the dead-but-documented code.
Verified: tsc --noEmit, pnpm lint (0 warnings), 337 unit + 366 integration
tests, pnpm build all green.
A lista de municípios vira a fila de decisão, sem rota nova, sem coluna nova
e sem migration.
Fase 0 corrige a meta sintética do E8, que repartia a meta estadual
proporcionalmente só ao teto do campo e ignorava a votação própria (meta 2.911
para Vitória da Conquista, de 5.005 votos em 2022; 813 para Campo Formoso, de
47). `deriveSuggestedGoalsByScenario` substitui `decomposeStateGoal` e ancora a
meta na votação de 2022 por cenário — pessimista = base × (1 − margin), central
= base, otimista = base × (stateGoal ÷ Σ base), com clamp. `goalCoverage` passa
a receber `SuggestedGoalByScenario`, deixando `expectedVotes[S] ??
suggestedGoal[S]` simétrico. Só descrições do global mudaram.
Fase 1 adiciona frescor e ordenações: `declaredAt`/`estimatedAt` no select do
agregado de pledges (`lastPledgeAt`), `lastSignalAt` no view model via
`resolveMunicipalityLastSignalAt` (mesmo helper para o comparador do servidor e
a célula), e as sort keys `deficit` (novo default do staff) e `frescor`,
derivadas em memória no cenário central.
Fase 2 dobra os sinais nas células existentes: "há N dias" na coluna de última
atualização (frio ≥ 21 dias, em âmbar — vermelho já é da prioridade), badge
"sem responsável" em prioridade alta sem assessor, coluna da vergonha no
detalhe da métrica de assessoria, tooltip de cobertura nomeando o cenário e
copy Praças→Municípios.
Cortes: votos em jogo → B13, LQ/captura → E10, coluna dedicada de déficit
desnecessária.
Nova rota staff-only /campanha/conceitos (glossário curado em
src/lib/campaignIntelligenceConcepts.ts, revisado junto das fórmulas
que descreve em municipalityPotential.ts/goalCoverage.ts) com
descoberta por "Saiba mais" nos tooltips do card "Conta da cadeira" e
entrada fixa no rodapé da sidebar (staffSecondaryNav). Corrige defeito
E8 de formatElectionNumber (meta fracionária lida como cem mil em
pt-BR). Ajustes pós-/simplify: MetricExplanation.conceptID obrigatório,
href da sidebar desacoplado do módulo de conteúdo (client bundle).
capture-review-debts (auto-confirm) triageou os achados restantes do
/impeccable critique de MunicipalityGoalAccountCard: os 3×P1+P2+P3
confirmados já foram fechados nesta sessão; o resto (naming, redesenho
hipotético de Captura/Share intracampo, disclosure não assentado para
futuras métricas) é cosmético ou prematuro — anotado como defer+gatilho
em "Adiado com gatilho" em vez de virar item novo no roadmap.
- MunicipalityHoverTooltip/MunicipalityGoalAccountCard: hover/focus tooltips on
the 4 "Conta da cadeira" diagnostic numbers, hardened per /impeccable
critique (touch dead-end fix via controlled open + pointerup toggle +
outside-tap dismiss, tooltip no longer covers "Cobertura da meta", clearer
two-tier copy, distinguishable button trigger, thicker 0% progress bar).
- seed-tse-results.mjs/electionResultsBuild/electionResultsParse: seed also
imports presidente/governador for 2014/2018 (previously deputado federal
only), with vote-em-transito duplicate merging so the unique constraints
hold; artifact/formulas stay 2022-only by design.
- Registered E18 (documentacao-conceitos-campanha) roadmap item/plan for a
future /campanha/conceitos glossary page.
Capture header filters, column visibility, and named saved filters (sidebar shortcuts) in the roadmap, and document why drag-and-drop column reorder stays deferred.
First regional surface in /campanha: a sortable 27-TI overview table on the
Início staff dashboard, next to the municipal map. Per-TI aggregates only
(sums and ratios of aggregates — MAUP safeguard); Metropolitano decomposed
into Salvador (19 zones) vs. demais RMS. Loader is server-only with
overrideAccess:true (regional context, not management; TI-level exposure
only); pure rollup stays client-safe for the sortable table. First slice of
E12, which extends with capture/LQ/meta coverage.
Meta Bom/Regular/Mínimo duplicated the estimate scenarios — keep a single municipality series (pessimista/média/otimista), backfill then drop the old columns, and map the spreadsheet onto expectedVotes.
- Compile docs/roadmap.md into a next-steps document (277→206 lines): R0–R5/M1–M5
tables and the delivered map/list item paragraphs compressed into 'Já entregue';
janelas, grafo and cortes list only open IDs; C10/C11/C8 fill-ins keep their
original triggers; C5 moved under 'A validar'.
- Record the production deploy of the destructive remodel chain (2026-07-23 Vercel
builds) across roadmap, AGENTS.md, the project notebook and plans — supersedes
every 'deploy pendente'; smoke pós-deploy + onboarding remain the open blockers.
- Fix AGENTS.md internal contradictions: Município locked-decisions bullet (435,
Camaçari whole, candidate role), campaignUser role enum, deploy-checklist item 7
as historical, access/* structure note, election-aggregates artifact +
election-tse revalidate runbook.
- Sync open plans to real identifiers (plaza*/nucleus* → municipality*): the
intelligence program (master + E8–E15/B13/C12 with artifact/caching context and
satisfied deps), B8 rescoped to Salvador ZE 1–19 only, WhatsApp D3–D5, D2, A6
(now the insight layer over stateDeputy), RS+, onda-0 smoke step.
- Close items verified done in code: C8 F4 (DRY de forms) complete, filtros-auto
shared pending shell, petition generateStaticParams select/depth; ledger the
surviving user-visible 'Praça' copy in src as new P2 debt.
- Banner delivered praça-era plans (production note + rename pointer); mark
remodelagem-pracas.md superseded and remodelagem-municipios.md delivered.
- TECH-DEBT smell statuses, TESTING RBAC row, README quality gates, campanha
UI rules updated to current component names.
Rename the operational unit "Praça"/"Núcleo" to "Município" (code identifier
`municipality`) and land the 2026-07-23 course changes:
- New `candidate` role with unrestricted visibility (`isCampaignStaff` now
includes it) alongside coordinator/advisor; leader is locked down to the
supporter contact tool only.
- Demandas become staff-only; dobradinhas modeled via a `stateDeputy` entity.
- Camaçari consolidated to a single município (ZE 170/171 aggregated);
Salvador keeps its 19 zone municípios.
- Map moves to the staff dashboard; `/campanha/municipios` is list/overview.
- Vote pledges keep the declared vs estimated (scenario) asymmetry; leaders
never see estimates.
Destructive migration for the campaign vertical (drops nucleus/plaza-era
tables, wipes campaign rows, seeds 435 municípios). Public-site data untouched.
Includes the post-delivery /simplify cleanups: shared reloadStaffActor /
reloadCoordinatorActor helpers, req.context cache for getFreshCampaignUser,
parallelized dashboard loads, candidate dashboard-copy fix, and dead
leader-dashboard / roleKind code removal.
Capture field evidence from the anchor session, update CUSTOMER/roadmap plans, and add vote-scenario and internal WhatsApp bridge specs with interview audio and transcripts.
Enables @payloadcms/plugin-import-export on signature (flattened contact/petition columns) and contact (native fields) so operations can download filtered lists for external ESP/SMS workflows.
Embeds approved literature→persona→interview research in docs/research/, adds inteligencia-campanha master plan with child specs, updates roadmap/PRODUCT/AGENTS, and extends roadmap skills with data-presentation guidance.
Unify list and /editar server actions in plazaStaffFormActions.ts so B9 inline edits and the edit page share one implementation without behavior changes.
Ship static zone-to-neighborhood mapping for Salvador/Camaçari Praças-zona, overview UI card, tests/fixture, and roadmap/plan updates including F2 prep follow-ups from capture-review-debts.
Keep GeoJSON stable across metric/scale/hover changes via pathByKeyRef and O(2) restyle; extract bahiaMapStyle helpers with unit tests and close B10/B11 perf debt refs in plans.
Promotes the deferred B7 fitBounds follow-up into its own roadmap item and plan so the map can zoom to the filtered region without re-zooming on year/scale changes.
Deduplicate pledge aggregation via loadPlazaListPageBundle, add plazaRevalidation with slug-scoped detail paths after inline saves, and document the fill-in as shipped.
Adds valid-votes denominators to the map bundle, a Total vs % dos válidos selector with fixed 0–100% coloring, and readout/legend alignment via scaleMax; updates roadmap and post-simplify debt docs.
Adds polygon highlight, vote readout, and navigation (desktop click / mobile 2nd tap) on the filtered Praças choropleth, with simplify cleanup and B6 plan updates for incremental setStyle.
Wire buildPlazaListWhere into loadPlazaMapBundle, export PlazaListSearchParams
from plazaUi, add integration tests, and mark B7 delivered in roadmap/docs.
Add staff-only expectedVotes with migration, edit flow, and expectedVotes ?? pledge fallback across map, overview, and dashboard; document delivery and the A9+ loader dedup fill-in on the roadmap.
Let marketing configure a numeric facebookPixelId per petition in Payload, fire PageView on load and Lead after a successful signature, and mark the roadmap item delivered with deferred follow-ups documented.
436 seeded Praças (municipality-based; per-TSE-zone in Salvador/Camaçari) become
the operational unit; roles renamed to coordinator/advisor/leader with advisors
scoped to administered Praças. Leadership is one record per person across many
Praças/organizations; vote pledges split leader-declared vs staff-estimated
(estimates never serialized to leaders). Adds organizations, demand workflow
with staff-only cost/receipts, action-plan results with deputy presence, manual
political trend, multi-candidate comparison and the diverging red/white/blue
map mode. Migration 20260721_020109_remodel_plazas deliberately resets the
campaign vertical in production (public site untouched); test suite ported to
the new model (unit 187 / int 306 / e2e 9 green).
Switch election geography queries from cityName to TSE cityCode via a static Bahia map and nucleusElectionGeography module, with simplify cleanup and plan updates for F3–F5 follow-ups.
Surface brancos/nulos/abstenções as mobilization opportunity on nucleus detail and list overview, with loader aggregate and unit tests; register pending int coverage in escala-dry-pos-e2.
Extract dashboard cards into focused components (queues, upcoming plans, leadership status, recently visited, choropleth legend), compile the roadmap for outcome-oriented tracking, document the customer job and improve-app journey, and tighten roadmap skills with decision-quality gates.