From c53add3f8fb37289edfeda5e004d1c8d0e9ce69b Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 1 Aug 2026 06:57:30 +0000 Subject: [PATCH] =?UTF-8?q?docs:=20registra=20B92=E2=80=93B94=20(Issues=20?= =?UTF-8?q?#92=E2=80=93#94)=20p=C3=B3s-gate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gate 2026-08-01: sem título de seção; geo só se permission granted; fatia em três entregáveis confirmada. Planos ready com Issue #N. --- .../wizard-municipio-sugestoes-chassis.md | 25 +++++++++---------- .../wizard-municipio-sugestoes-continuity.md | 14 +++++------ docs/plans/wizard-municipio-sugestoes-geo.md | 25 ++++++++++--------- 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/docs/plans/wizard-municipio-sugestoes-chassis.md b/docs/plans/wizard-municipio-sugestoes-chassis.md index 784b76f0..1a8f26ea 100644 --- a/docs/plans/wizard-municipio-sugestoes-chassis.md +++ b/docs/plans/wizard-municipio-sugestoes-chassis.md @@ -1,8 +1,8 @@ # Empty state do wizard — chassis + ranking de esquecidos -Status: rascunho +Status: ready Atualizado em: 2026-08-01 -Issue: — +Issue: #92 Priority: P1 Model: composer-2.5 Impeccable: B — encaixe em `WizardMunicipalitySearchStep` (passo 1 dos wizards `/campanha/acoes/`) @@ -32,13 +32,12 @@ Brief compacto: │ ┌─ Buscar município ─────────────────────────────────┐ │ │ │ Nome do município… │ │ │ └────────────────────────────────────────────────────┘ │ -│ Prováveis │ │ · Cairu · Baixo Sul · 2022 … [alta?] │ │ · Valença · … │ │ · … (até ~8; select = avança com ?municipio=) │ └────────────────────────────────────────────────────────┘ - Fora do frame: strip de ações do Início; Continuity (B93) - e geo (B94) entram depois como linhas prefixadas. + Sem título de seção — mesma região de resultados da busca. + Continuity (B93) e geo (B94) entram depois como linhas prefixadas. ``` ## Dados → decisão → apresentação @@ -61,7 +60,7 @@ Este item é o **chassis + ranking server de esquecidos**. Continuity (visitados ## Objetivos -- Quando `!query.isActive` no passo de município do wizard: mostrar seção **Prováveis** (copy craft; default “Prováveis”), não o deserto. +- Quando `!query.isActive` no passo de município do wizard: preencher a **mesma região de resultados** com hits sugeridos (sem título de seção — decisão de produto 2026-08-01), não o deserto. - Novo modo tipado no `home-search` (recomendação: `mode: 'wizard-municipality-suggest'`) distinto de `suggest` (B68) e de `wizard-municipality` (B60 search) — política e payload próprios; staff-only (layout `acoes/` já gateia). - Rank puro client-safe em `src/lib/` (irmão de `homeSearchSuggest.ts`), pinado em unit: 1. **Primário:** mais dias sem sinal primeiro (`lastSignalAt` via `resolveMunicipalityLastSignalAt`; `null` = mais frio). @@ -76,14 +75,14 @@ Este item é o **chassis + ranking server de esquecidos**. Continuity (visitados - **Modo dedicado `wizard-municipality-suggest`, não reusar `suggest` do Início.** Wizard é ritual ação→local; B68 filtra CG a `priority === 'alta'` e usa déficit — aqui o pedido é **esquecidos do escopo inteiro** com desempates E14/tendência/classe/votos. **Rejeitado:** chamar `loadHomeSearchSuggestions` no wizard (política errada); search com `q=""` (contradiz B66/B68). - **Primário = frescor (`lastSignalAt`), não só `lastUpdateAt`.** Mesma semântica E9/B68 (max update × pledge). **Rejeitado:** só `municipality.updatedAt` do Payload (ruído de admin); só `lastUpdateAt` (ignora pledges). - **Desempates na ordem do pedido de produto** (envolvimento → tendência → classe → votos), com pesos já existentes (`engagementLevelRank`, ordem de tendência acima, `territorialClassSortWeight`, votos nominais 2022 do artifact/scope). **Rejeitado:** déficit de meta como desempate neste item (B68 já cobre no Início; misturar duas “inteligências” no mesmo empty confunde); LQ contínuo no lugar da classe. -- **Lista flat com título de seção; reason labels por linha ficam para B93/B94** (neste slice todas as linhas são “esquecidos”). **Rejeitado:** cards; multi-grupo neste appetite. -- **i18n / naming:** identificadores `wizardMunicipalitySuggest`, `rankWizardMunicipalitySuggestions`, `loadWizardMunicipalitySuggestions`; strings pt-BR (“Prováveis”, …). +- **Lista flat na região de resultados, sem título de seção** (produto 2026-08-01). Reason labels por linha ficam para B93/B94 (neste slice todas as linhas são “esquecidos”). **Rejeitado:** heading “Prováveis”/“Sugestões”; cards; multi-grupo neste appetite. +- **CG = escopo completo frio-primeiro** (não filtrar a `priority === 'alta'`). Prioridade alta continua só como indicador na linha. **Rejeitado:** copiar filtro B68 (política de omnibox, não de ritual). +- **Votos de desempate = nominais 2022 do candidato (artifact).** **Rejeitado:** estimado central (live/cache). +- **i18n / naming:** identificadores `wizardMunicipalitySuggest`, `rankWizardMunicipalitySuggestions`, `loadWizardMunicipalitySuggestions`; copy de empty tipado permanece a de B60. ## Questões em aberto -- **Título da seção?** **Opções:** A “Prováveis” | B “Sugestões” (paridade B68) | C “Para esta ação”. **Recomendação:** **A** — distingue do omnibox do Início. _(assumido — craft)_ -- **CG inclui municípios `priority !== 'alta'`?** **Opções:** A sim, escopo completo frio-primeiro | B só `alta` como B68. **Recomendação:** **A** — o pedido é esquecidos + desempates de investimento; prioridade alta já é sinal na linha (`showPriority`). _(assumido — validar com produto)_ -- **Votos = série Solla 2022 no município (artifact) vs estimativa central de pledges?** **Opções:** A votos 2022 nominais | B estimado central. **Recomendação:** **A** — estável, sem live cache, já no readout do hit. _(assumido)_ +- Nenhuma após gate 2026-08-01. ## Abordagem proposta @@ -102,7 +101,7 @@ Componentes: - **`src/lib/wizardMunicipalitySuggest.ts`** (puro): input tipado (`slug`, `name`, `lastSignalAt`, `engagementLevel`, `politicalTrend`, `territorialClass`, `votes2022`) + `rankWizardMunicipalitySuggestions(inputs, limit)` + constantes de ordem de tendência; unit-pinned. - **`src/utilities/homeSearch/loadWizardMunicipalitySuggestions.ts`** (`server-only`): `loadMunicipalityScope` com `extraSelect` (`lastUpdateAt`, `engagementLevel`, `politicalTrend`, …); classe via helper E10 já usado na lista/map; votos 2022 do artifact/`bahiaElectionAggregates` (ou campo já no scope se existir); `overrideAccess: false`. - **Rota** `home-search/route.ts` + schema zod discriminado: ramificar o novo mode; resposta no shape `WizardMunicipalitySearchSuccessResponse` (ou irmão com `resultKind: 'wizard-suggest'`). -- **`WizardMunicipalitySearchStep`**: fetch suggest no idle; cancelar ao digitar; render seção + hits; empty tipado só quando search ativo e 0 hits. +- **`WizardMunicipalitySearchStep`**: fetch suggest no idle; cancelar ao digitar; render hits na região de resultados (sem heading); empty tipado só quando search ativo e 0 hits. - **Reuse:** `HomeSearchHitRow`, `HomeSearchMunicipalityVoteTrailing`, `postCampaignJson`, `useHomeSearchQuery`, copy em `campaignWizardCopy.ts`. - **Migration:** Sem migration, sem collection, sem Consent. @@ -133,7 +132,7 @@ Componentes: ## Referências -- GitHub Issue — (após register) +- GitHub Issue #92 - [`WizardMunicipalitySearchStep.tsx`](../../src/components/campaign/shared/WizardMunicipalitySearchStep.tsx) - [`homeSearchSuggest.ts`](../../src/lib/homeSearchSuggest.ts) / [`loadHomeSearchSuggestions.ts`](../../src/utilities/homeSearch/loadHomeSearchSuggestions.ts) - [`busca-municipio-wizard.md`](busca-municipio-wizard.md) (B60 — adiados) diff --git a/docs/plans/wizard-municipio-sugestoes-continuity.md b/docs/plans/wizard-municipio-sugestoes-continuity.md index 59a39c29..af63e74b 100644 --- a/docs/plans/wizard-municipio-sugestoes-continuity.md +++ b/docs/plans/wizard-municipio-sugestoes-continuity.md @@ -1,8 +1,8 @@ # Empty state do wizard — continuity (visitados + última ação) -Status: rascunho +Status: ready Atualizado em: 2026-08-01 -Issue: — +Issue: #93 Priority: P2 Model: composer-2.5 Impeccable: B — prefixo client no empty de `WizardMunicipalitySearchStep` (após B92) @@ -28,13 +28,12 @@ Brief compacto: ```text ┌─ Wizard passo município (idle, pós-B92) ───────────────┐ │ [input busca…] │ -│ Prováveis │ │ · Itabuna · … · Última ação │ │ · Cairu · … · Visitado │ │ · Valença · … · Visitado │ │ · … (fill B92 esquecidos, dedup) │ └────────────────────────────────────────────────────────┘ - Geo (B94) pode ocupar 1 slot acima de Continuity. + Sem título de seção. Geo (B94) pode ocupar 1 slot acima. ``` ## Dados → decisão → apresentação @@ -69,12 +68,13 @@ Já existe `teqo:campaign:recent-visits` (`recentVisits.ts`, Quadro). B68 **adio - **Gravar última ação no success do write, não no select do passo 1.** Select sem commit não é “executou ação”. **Rejeitado:** gravar no `router.push(?municipio=)` (falso positivo se abandonar). - **Reusar `recentVisits` para acessos; storage separado para last-acted.** Semânticas diferentes (dwell 2s vs write). **Rejeitado:** sobrecarregar `RecentVisitEntry` com `kind: 'acted'`. - **Merge só no idle; search tipado ignora continuity.** Paridade B68/B92. +- **Sem título de seção** (gate 2026-08-01) — só linhas na região de resultados, com reason na secondary. - **i18n:** `campaignLastActedMunicipality` / `recordLastActedMunicipality` / `listWizardContinuitySlugs`; copy “Última ação”, “Visitado”. +- **Prefixo: 1 last-acted + até 3 visitados**; filtrar fora da carteira. Cap total da lista ~8 com B92/B94. ## Questões em aberto -- **Quantos visitados no prefixo?** **Opções:** A 3 | B 5 | C todos os 8 do storage. **Recomendação:** **A** (3) — deixa espaço para esquecidos/geo no cap 8. _(assumido)_ -- **Escopo assessor:** visitado fora da carteira (mudança de advisors)? **Opções:** A ocultar | B mostrar e falhar no select. **Recomendação:** **A** — filtrar contra slugs do payload suggest ou prop `accessibleSlugs`. _(assumido)_ +- Nenhuma após gate 2026-08-01. ## Abordagem proposta @@ -120,7 +120,7 @@ Componentes: ## Referências -- GitHub Issue — (após register) +- GitHub Issue #93 - [`recentVisits.ts`](../../src/utilities/recentVisits.ts) · [`visitados-recentemente.md`](visitados-recentemente.md) - [`wizard-municipio-sugestoes-chassis.md`](wizard-municipio-sugestoes-chassis.md) (B92) - AGENTS.md — sem Consent para storage local de UX autenticada (precedente B14/visitados) diff --git a/docs/plans/wizard-municipio-sugestoes-geo.md b/docs/plans/wizard-municipio-sugestoes-geo.md index c1ba50f1..66c222a6 100644 --- a/docs/plans/wizard-municipio-sugestoes-geo.md +++ b/docs/plans/wizard-municipio-sugestoes-geo.md @@ -1,8 +1,8 @@ # Empty state do wizard — município mais próximo (geo) -Status: rascunho +Status: ready Atualizado em: 2026-08-01 -Issue: — +Issue: #94 Priority: P2 Model: composer-2.5 Impeccable: B — 1 linha prefixada no empty de `WizardMunicipalitySearchStep` (após B92) @@ -28,13 +28,13 @@ Brief compacto: ```text ┌─ Wizard passo município (idle) ────────────────────────┐ │ [input…] │ -│ Prováveis │ │ · Salvador — ZE 5 · … · Perto de você (~1,2 km) │ │ · … (B93 continuity) │ │ · … (B92 esquecidos) │ └────────────────────────────────────────────────────────┘ - Sem permissão / fora da BA / unsupported: linha some; - lista B92/B93 permanece. + Sem título de seção. Só resolve se permission já granted + (prompt de geo já ocorre ao abrir o Quadro — produto 2026-08-01). + Sem permissão / fora da BA / unsupported: linha some. ``` ## Dados → decisão → apresentação @@ -55,8 +55,8 @@ O pedido (2026-08-01) inclui o mesmo sinal no empty do **wizard**. O passo 1 hoj - No idle do wizard, tentar resolver município mais próximo **no escopo do ator** reusando `requestCurrentPosition` / `resolveNearbyMunicipality` / loaders lazy de geometria. - Página `acoes/[slug]` (passo busca) passa prop `accessibleMunicipalities: AccessibleMunicipality[]` (slug/name/ibgeCode) a partir do scope — ou o client usa só os slugs do suggest B92 **mais** um payload mínimo RSC (recomendação: prop RSC, porque suggest é top-8 e o nearest pode estar fora do top frio). -- Prompt automático: **respeitar** `hasPromptedThisSession` de B14 (não re-assaltar se o Quadro já pediu; se wizard é a 1ª superfície da sessão, um prompt basta). -- Falhas (`denied` / `timeout` / `unsupported` / fora da BA / outOfScope sem nearest): **silêncio** — não montar linha de erro no ritual (diferente do card do Quadro que explica); usuário digita. +- **Só resolve se a permissão já está `granted`** (gate 2026-08-01): o prompt de geo já ocorre ao abrir (Quadro B14). Wizard **não** dispara `requestCurrentPosition` em `prompt`/`denied`/`unknown` — zero surpresa no ritual. +- Falhas / não-granted / fora da BA / outOfScope sem nearest: **silêncio** — não montar linha de erro nem CTA; usuário digita. - `kind: 'inScope'` → uma hit row com reason; select = auto-avanço. - Sem migration / Consent / POST de coordenadas. @@ -64,14 +64,15 @@ O pedido (2026-08-01) inclui o mesmo sinal no empty do **wizard**. O passo 1 hoj - **Client-only matching (paridade B14).** **Rejeitado:** POST lat/lng; PostGIS; artefato de centroides commitado (já revertido em B14). - **Prop RSC de municípios acessíveis** para o matcher (não só top-8 do suggest). **Rejeitado:** resolver só dentro dos 8 esquecidos (falso “perto” se o município real ficou de fora do rank frio). +- **Geo no wizard = só `granted` (produto 2026-08-01).** Prompt já foi dado ao abrir o app/Quadro; não re-pedir nem CTA no ritual. **Rejeitado:** prompt automático no mount do wizard; CTA “Usar localização” neste item. - **Fail soft sem UI de erro no wizard.** Ritual não deve virar troubleshooting de GPS. **Rejeitado:** copiar o card B14 inteiro para dentro do shell. -- **Uma linha, não card.** **Rejeitado:** embutir `NearestMunicipalityCard`. +- **Uma linha, não card; sem título de seção.** **Rejeitado:** embutir `NearestMunicipalityCard`; heading “Prováveis”. +- **Salvador multi-ZE `zoneCity` / ambíguo: omitir a linha** — wizard exige `municipality` atômico. **Rejeitado:** deep-link para lista filtrada (sai do ritual). - **i18n:** reusar `formatDistanceKm`; reason “Perto de você”; helpers `useWizardNearestMunicipality` se o efeito merecer nome (senão lógica no step até extrair no 2º call site). ## Questões em aberto -- **Prompt automático no mount do wizard se a sessão ainda não pediu?** **Opções:** A sim (paridade Quadro) | B só se permissão já `granted` | C CTA explícito “Usar minha localização”. **Recomendação:** **B** no v1 do wizard (zero surpresa no meio do ritual) + se `granted`, resolve quieto; CTA curto se `prompt`/`denied` e craft quiser. _(assumido — validar com produto; se campo pedir paridade total com Quadro, subir para A)_ -- **Salvador multi-ZE outOfScope / zoneCity:** seguir B14 (lista filtrada no Quadro). No wizard: **Opções:** A omitir linha | B deep-link impossível sem município. **Recomendação:** **A** omitir — wizard exige `municipality` atômico. _(assumido)_ +- Nenhuma após gate 2026-08-01. ## Abordagem proposta @@ -113,12 +114,12 @@ Componentes: ## Adiado com gatilho -- **CTA “Usar localização” quando permission ≠ granted.** Revisitar se sessão observada mostrar staff recusando o prompt silencioso e pedindo botão. +- **CTA “Usar localização” quando permission ≠ granted.** Revisitar se sessão observada pedir botão explícito no wizard (hoje o prompt vive só no Quadro). - **Centroid artifact** só se o lazy da malha pesar no mid-tier Android em campo. ## Referências -- GitHub Issue — (após register) +- GitHub Issue #94 - [`municipio-mais-proximo.md`](municipio-mais-proximo.md) (B14) - [`campaignGeolocation.ts`](../../src/utilities/campaignGeolocation.ts) · [`municipalityProximity.ts`](../../src/lib/municipalityProximity.ts) - [`wizard-municipio-sugestoes-chassis.md`](wizard-municipio-sugestoes-chassis.md) (B92)