diff --git a/.cursor/rules/projects/nucleos-eleitorais.mdc b/.cursor/rules/projects/nucleos-eleitorais.mdc index 09e8c1f5..870ba4f9 100644 --- a/.cursor/rules/projects/nucleos-eleitorais.mdc +++ b/.cursor/rules/projects/nucleos-eleitorais.mdc @@ -7,6 +7,7 @@ alwaysApply: false ## Status +- **B71 entregue em código (2026-07-30):** polimento visual dos resultados de busca no Início (UX-1) — `src/lib/homeSearchUi.ts` (`HOME_SEARCH_HIT_ROW_WRAPPER_CLASS` = bleed + hover + `focus-within`; heading/list); `HomeSearchHitRow` faixa full-bleed `-mx-4 px-4 md:-mx-6 md:px-6` (mantém `onMouseDown` preventDefault de B66); todos os `HomeSearch*Group` com `ul list-none` e título `text-xs` sentence-case (sem `uppercase`/`tracking-wide`). Unit `homeSearchUi.unit.spec.tsx`. Sem migration/action/JSON. Plano: [`polimento-resultados-busca-inicio.md`](../../../docs/plans/polimento-resultados-busca-inicio.md). - **B66 entregue em código (2026-07-30):** modo focado da busca no **focus** (emenda B47) — `homeSearchUiFocused` (`inputFocused || query.isActive`) já no contrato/hook; overlap B68 (sugestões no focus vazio). **Nesta entrega:** `CampaignHomeLayout` retrai summary+spacer (`data-slot="home-chrome"`) e actions com grid `0fr/1fr` + opacity 220ms (`motion-reduce:transition-none`) em vez de `hidden`; `md:flex-none` no chrome; `HomeSearchHitRow` `onMouseDown` preventDefault (blur→click); e2e focus sem digitar + regressão com digitação. Sem migration. Plano: [`modo-focado-busca-no-focus.md`](../../../docs/plans/modo-focado-busca-no-focus.md). - **B61 entregue em código (2026-07-29):** etapa de ajuste de votos no wizard A1 — `WizardExpectedVotesStep` substitui o stub B60 em `atualizar-votos` com `?municipio=`; três passos explícitos média→pessimista→otimista via `?cenario=`; atalhos `2×`/±50/±100; validação client com jump+warning (`getWizardVoteViolation`); **um POST batch** ao concluir otimista (`POST /campanha/municipios/expected-votes`). Helpers em `wizardVoteEstimate.ts` + `wizardActionHref` estendido. Sem migration/Consent. Unit `wizardVoteEstimate`; e2e avanço de cenário + violação. Plano: [`ajuste-votos-wizard.md`](../../../docs/plans/ajuste-votos-wizard.md). Desbloqueia wiring A1 / **B64** (prefill votos). - **B62 entregue em código (2026-07-29):** modelo de sinal simplificado — `municipalityUpdate` kind `sinal` agora é só `signalType` + `body`; migration `20260730_010601_simplify_municipality_signal_fields` dropa `signal_source`/`triangulated` (o gerador reemitiu `ADD VALUE 'adiada'` por drift de snapshot — removido à mão, e o snapshot novo sara a cadeia); labels/descriptions dos 5 tipos reescritas para a mesa (`Rede esfriou`, `Adversário apareceu`, `Alguém pediu algo` — sem "broker" no modelo de sinal; `activity.origin` `pedido_broker` e a copy do suggestionCatalog ficaram fora por decisão da sessão). Forms: `MunicipalitySignalFields` (lista B26) e o bloco inline de `MunicipalityUpdateForm` perderam Fonte/Triangulado; feed/dossiê (`MunicipalityUpdateFeed` + `municipalityUpdatePageData`) só exibem o badge do tipo. **E11: presença de sinal de adversário lê como confirmada — triage 1** (decisão do usuário: "eles não vão adicionar sinais improváveis"), `adversarySignal: { present: true } | null`, fator único "Sinal de adversário registrado", glossário E18 alinhado. Fixa B63. Bônus: teste e2e `campaignMunicipalities` "advisor scopes…" estava obsoleto desde B43 (home da liderança) — atualizado para `/campanha/contatos` + redirect pós-B43, e o pin de bypass do `municipalityElectoralBaseline` baixado 9→8 (drift pré-existente). Gate: tsc/lint/format/cycles/knip(P3 pré-existente)/876 unit/489 int/e2e alvo verde/build (`/campanha` 233 kB); Aikido 0 findings. Plano: [`simplificar-modelo-sinal.md`](../../../docs/plans/simplificar-modelo-sinal.md). Desbloqueia **B63** (wizard registrar sinal). diff --git a/AGENTS.md b/AGENTS.md index bdb5804d..8d5b6f8e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -70,6 +70,7 @@ Backlog consolidado (bloqueadores, site, campanha, white-label): [`docs/roadmap. **Recently resolved (2026-07-25): Engineering Consolidation Pass 2** (tracker: [`docs/IMPROVE-CODE-QUALITY-PLAN.md`](docs/IMPROVE-CODE-QUALITY-PLAN.md) § Pass 2; architecture: [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md); agent map: `.cursor/rules/codebase-map.mdc`). Highlights: **W1 sistema de listas** — colunas como dado em `CampaignTable` (seams B17/B18), URL state compartilhado (`campaignListUrl` + módulos por domínio; o god module `municipalityUi.ts` virou `municipalityListUrl`/`municipalityListFilters`/`municipalityLabels`/`municipalitySignal`), shells (`CampaignListFooter`, `CampaignListEmptyState`), 8 superfícies migradas (municípios, lideranças, organizações, dobradinhas, demandas, apoiadores, assessores, atividades-shells), B16+ absorvido (`useOptimistic`, hrefs por serializador canônico, facet por slugs, facets no mesmo `Promise.all`); **W2** — fronteiras: `slug`/`phone`/`wordStartFilter`/`voteEstimate` movidos para `lib/`, 21 loaders `server-only`, `campaignRoles.ts` client-safe (sidebar sem o barrel de access), `votePledgeViews` (contract) vs `votePledgeData` (loaders), ciclo supporter quebrado, `components/campaign` em 15 subpastas de domínio; decisão D1: sem `src/domains/`, sem ports-and-adapters; **W4a** — `electionInsights.ts` (941 linhas, 2 exports vivos) deletado; sobreviventes em `electionFormat.ts`/`voteTrend.ts`; E10 nasce limpo; **W4b** — knip `exports`/`types`/`enumMembers` em **ERROR** no CI (0 findings; kit ui sem peças mortas); **W4c** — tabs das páginas de detalhe extraídas (`MunicipalityDetailTabs`, `ActivityOverviewTab`) + factory `detailTabUi`; **W4d** — `runCampaignFormAction` fecha o C8 F4 (13 ações em 7 arquivos; exceções documentadas); **W4e** — tipos de fonte única; **W4f** — copy "Praça"→"Município" varrida (apoiadores desambiguado: cidade do contato = "Cidade"); **D3** — consent do WhatsApp por chave estável (`whatsapp-inscricao`, fail-closed). Suites: 46 unit / 48 int / 7 e2e. +**Recently resolved (2026-07-30):** **B71** Polimento visual dos resultados de busca no Início — `src/lib/homeSearchUi.ts` centraliza bleed (`-mx-4 px-4 md:-mx-6 md:px-6`), heading discreto (`text-xs` sentence-case) e `ul list-none`; `HomeSearchHitRow` pinta hover/focus na faixa full-bleed; todos os `HomeSearch*Group` alinhados. Sem migration/action/contrato JSON. Plano: [`docs/plans/polimento-resultados-busca-inicio.md`](docs/plans/polimento-resultados-busca-inicio.md). **Recently resolved (2026-07-29):** **B62** Simplificar modelo de sinal — `municipalityUpdate` kind `sinal` is now `signalType` + `body` only: migration `20260730_010601_simplify_municipality_signal_fields` drops `signal_source` and `triangulated` (the generator re-emitted `ADD VALUE 'adiada'` from snapshot drift — removed by hand; this migration's committed `.json` heals the chain), and the five signal-type labels/descriptions were rewritten for the field team (`Rede esfriou`, `Adversário apareceu`, `Alguém pediu algo` — no "broker" in the signal model; `activity.origin`'s `Pedido de broker` and suggestionCatalog copy were explicitly left out by session decision). `MunicipalitySignalFields` (B26 list control) and the inline block in `MunicipalityUpdateForm` lost Fonte/Triangulado; `municipalityUpdatePageData` + `MunicipalityUpdateFeed` (detail + dossier) render only the type badge. **E11 changed semantics: any adversary signal in the window reads as confirmed — P1 triage 1** (session decision, replacing the triangulated/single-source split), `MunicipalityTriggerInput.adversarySignal: { present: true } | null`, single factor copy, E18 glossary aligned. Bonus gate fixes: the `campaignMunicipalities` "advisor scopes…" e2e was stale since B43 (leader home → `/campanha/contatos`) and was updated, and the `municipalityElectoralBaseline` bypass pin dropped 9→8 (pre-existing main drift). Gate: 876 unit / 489 int / targeted e2e green / build; Aikido 0 findings. Plano: [`docs/plans/simplificar-modelo-sinal.md`](docs/plans/simplificar-modelo-sinal.md). **Recently resolved (2026-07-29):** **B59** Chassis do wizard de campanha — rotas staff em `/campanha/acoes/` (`campaignActionRoutes.ts`, `campaignActionEntryHref`), layout `acoes/layout.tsx` (gate staff, coluna `max-w-lg`), `CampaignWizardShell` (voltar mobile, caption de município sticky, `trailingAction`, foco no `h1` ao trocar passo), cinco páginas-ponte até B60 e strip do Início com `href` nos fluxos wizard. Sem migration. Plano: [`docs/plans/chassis-wizard-campanha.md`](docs/plans/chassis-wizard-campanha.md). diff --git a/docs/plans/polimento-resultados-busca-inicio.md b/docs/plans/polimento-resultados-busca-inicio.md index a07c8f56..437b9843 100644 --- a/docs/plans/polimento-resultados-busca-inicio.md +++ b/docs/plans/polimento-resultados-busca-inicio.md @@ -1,7 +1,7 @@ # Polimento visual dos resultados de busca no Início -Status: rascunho -Atualizado em: 2026-07-29 +Status: entregue (2026-07-30) +Atualizado em: 2026-07-30 — as-built: `src/lib/homeSearchUi.ts` (bleed/heading/list); `HomeSearchHitRow` full-bleed `-mx-4 px-4 md:-mx-6 md:px-6` + hover na faixa; todos os `HomeSearch*Group` com `text-xs` sentence-case (sem `uppercase`) e `ul list-none`; unit `homeSearchUi.unit.spec.tsx`; sem migration. Item do roadmap: [docs/roadmap.md](../roadmap.md) (Trilha B — **B71**; chassis UX-1 / pós-B48) Impeccable: B — encaixe em `HomeSearchMunicipalityGroup` + `HomeSearchHitRow` (B48 ✓) Appetite: ~0,25–0,5 dia eng (CSS/markup; sem migration, action ou rota) @@ -83,7 +83,7 @@ Componentes: ## Adiado com gatilho -Nenhum neste item. +- **Extrair `HomeSearchGroup` shell** — cinco grupos repetem `
` + heading + `