Merge pull request #564 from fsolla/D8-restaurar-entradas-b183-c102-perdidas-do-docs-changelog-a
docs(D8): restaura entradas C102/C108 (e D6 truncada) do CHANGELOG — limpa lixo do rebase do C106
This commit is contained in:
commit
17ded2a86f
2 changed files with 88 additions and 5 deletions
|
|
@ -6,23 +6,23 @@ Conteúdo movido do `AGENTS.md` em 2026-07-30 (fatiamento do paradigma de agente
|
|||
|
||||
**Recently resolved (2026-08-10):** **OPS21** (Issue #538) — `REVALIDATE_SECRET` adicionada na **Vercel production** (projeto `solla/jorgesolla`): diagnóstico D6 confirmado (env ausente em `vercel env ls production`; `POST /api/revalidate` respondia `500` "not configured" em prod, quebrando o runbook pós-seed/mudança direta de DB). Segredo gerado com `openssl rand -hex 32` (valor via stdin, nunca argv), `vercel env add REVALIDATE_SECRET production`; **fallback necessário:** o deploy existente congelava as envs em runtime → `vercel redeploy` do último deploy de produção (2×, pois o primeiro `env add` via pipe herdou o `\n` do `openssl` e gravou valor de 66 chars — removido e re-adicionado limpo). Validação real em prod: sem secret → `401`; secret errado → `401`; secret certo → `200 { revalidated: true, tag: 'posts' }`; tag desconhecida → `400`. Preview não adicionada (projeto sem Git conectado — `vercel env add ... preview` exige branch, precedente D6). Sem código/migration/access/UI. Impl [`revalidate-secret-vercel-production-impl.md`](plans/revalidate-secret-vercel-production-impl.md).
|
||||
|
||||
**Recently resolved (2026-08-10):** **C108** (Issue #522) — sino de notificações: **abrir já lê** — `openCampaignNotifications` (action única) lista + marca tudo como lido em 1 round trip, substituindo `listCampaignNotifications` + `markAllCampaignNotificationsRead`; o badge zera na abertura sem clique e o botão "Marcar todas como lidas" deixa de existir. Painel limpo em qualquer tamanho: sem título "Notificações" visível (sr-only para a11y), sem contador, sem botão "Fechar"; desktop vira **modal central** (Dialog shadcn, X no canto superior direito, clique fora fecha — par responsivo Dialog/Drawer do C94 via `useIsMobile`); mobile segue bottom sheet com handle, safe-area e **skeleton de loading** (o painel não abre mais em branco durante o round trip). `markAllNotificationsRead` extraída para `src/utilities/notification/notificationList.ts` (owner-scoped com bypass documentado, idempotente, cap 200 mantido; int testado: marca só as próprias, deixa as do outro intactas); `readAt` saiu do contrato `NotificationListItem` (sem leitores após a remoção do destaque de não lida); copy de erro unificada em `CAMPAIGN_NOTIFICATION_LOAD_ERROR_MESSAGE`; `router.refresh()` re-sincroniza a instância irmã do outro header só quando algo foi marcado (race cross-tab documentado); foco visível nos itens e `role="alert"` no erro. P4-D atualizado no ledger — o batch sem transação agora dispara a cada abertura (self-healing). Testes: int (owner-scope + idempotência) e unit novos do bell (dialog limpo, refresh condicional, empty/error, sheet mobile). Sem migration, access, Consent ou schema. Intenção [`sino-notificacoes-leitura-auto-modal-desktop.md`](plans/sino-notificacoes-leitura-auto-modal-desktop.md); impl [`sino-notificacoes-leitura-auto-modal-desktop-impl.md`](plans/sino-notificacoes-leitura-auto-modal-desktop-impl.md).
|
||||
|
||||
**Recently resolved (2026-08-10):** **B184** (Issue #514) — no mobile (<768px), o filtro de listas `/campanha` virou o **padrão sem moldura do chassis `CampaignListOmnibox` (B127) — todas as listas**: label oculta (`input` carrega o nome via `aria-label`), campo sem borda/sombra (`md:` restaura o desktop), **form do filtro sticky sob a top bar** com linha separadora edge-to-edge, "Limpar" vira **X circular dentro do input** (aparece com chips OU busca digitada; slot sempre renderizado com `invisible` para a largura não pular; hit target 44px + círculo visual 28px; live region própria "Busca e filtros limpos." — limpar só busca não navega e o pending region ficaria mudo para AT), botão texto "Limpar" desktop-only. **Por que sticky no `<form>`:** sticky não escapa do containing block (o pai) — a coluna do input dentro do wrapper curto do omnibox "grudava" ~12px e rolava junto (medido); o form é o único wrapper filho do `CampaignPageShell` (altura total). **Exceção agenda (C101, merge anterior):** a `/campanha/agenda` já tinha o strip sticky próprio (`activity-agenda-filter-strip`) — mantido; o chassis ainda a cobre no campo/X/Limpar. Em municípios, adicionalmente: **"Salvar filtro" vira icon button no header mobile** (slot C94/C95, `SaveMunicipalityFilterControl presentation='icon'`; popover de nomear intacto; nome de rename é o contrato 2.5.3) e **cards edge-to-edge sem borda** com uma linha separando (`border-b last:border-b-0`, `-mx-4`, gate `md:`). "Nova atualização" (atualizações) — único trailing visível no mobile — foi para o header (mesmo padrão); `campaignMobileHeaderIconClassName` extraída (3º consumidor). E2E novo em `campaignMunicipalities.e2e.spec.ts` (390×844): label oculta, borda 0, sticky, X (limpa chips+busca, foco volta sem reabrir popover), salvar→renomear no header, cards com separador, desktop invertido (1280). Débito registrado no caminho: **D7** (sticky dos headers da tabela desktop morto — wrapper `overflow-x-auto` é o scroll container; medido). Sem migration, access, Consent. Intenção [`municipios-mobile-sem-moldura.md`](plans/municipios-mobile-sem-moldura.md); impl [`municipios-mobile-sem-moldura-impl.md`](plans/municipios-mobile-sem-moldura-impl.md).
|
||||
|
||||
**Recently resolved (2026-08-09):** **C103** (Issue #504) — o formulário de criação rápida da agenda ficou **usável de ponta a ponta no celular**: no narrow (mesmo breakpoint 640px do calendário), o sheet de criação abre **do topo** (`swipeDirection="up"` na primitiva `Drawer` — que já suportava top sheet; zero mudança em `Drawer.tsx`) preenchendo `100dvh-1rem`, o conteúdo **rola** num scroll container e o rodapé ("Mais detalhes" + "Salvar") é **fixo** — verificado em smoke com teclado aberto (viewport 280px: sheet encolhe via `dvh`, conteúdo rola 187/187px e o Salvar permanece visível). O form ganhou `variant: 'popover' | 'sheet'`: no sheet, **labels viram `sr-only`** (a11y e `getByLabelText` intactos), placeholders dão contexto ("Adicionar título _", "Município _", "Local (opcional)", "Adicionar responsáveis"), obrigatórios marcados com asterisco (título/município no placeholder, Início no trigger), campos empilhados **sem gaps com `divide-y`** e inputs/triggers sem borda (lista iOS do canvas). O **seletor de data/hora abre como bottom sheet aninhado** no mobile (`ActivityDateTimeField` ganhou `isNarrow`/`label`/`required`: conteúdo compartilhado Calendar+selects renderizado em `Drawer` com header "Início — <data>" + "Pronto"; desktop continua popover). Props backward-compatible: `placeholder`/`className` no `StrictCombobox`, `labelClassName`/`emptyText`/`triggerClassName` no `ResponsibleMultiSelect`. Decisão do smoke: swipe handle **removido** do top sheet (primitiva o posiciona no rodapé, contradizendo o gesto de swipe-up; continua nos bottom sheets). E2E mobile novo (viewport 390×844): sheet do topo (`y ≤ 1`), Salvar visível sem scroll, picker em bottom sheet com Pronto, evento aparece após salvar; unit narrow cobre placeholders/asterisco/Pronto. Desktop visualmente inalterado (B181 segue na fila para o clip do popover ≤720px). Sem migration/access/Consent/schema. Intenção [`agenda-mobile-form-criacao-usavel.md`](plans/agenda-mobile-form-criacao-usavel.md); impl [`agenda-mobile-form-criacao-usavel-impl.md`](plans/agenda-mobile-form-criacao-usavel-impl.md).
|
||||
|
||||
**Recently resolved (2026-08-09):** **D6** (Issue #521) — push no device fechado de ponta a ponta. **Diagnóstico com evidência por elo** (leitura read-only de prod): (1) **envs VAPID ausentes no Vercel production** (verificado com `vercel env ls production`) — elo raiz: sem elas o servidor nunca chama o web-push e o card de perfil desabilita "Ativar"; (2) consentimento `campanha-notificacoes-push` já publicado (Onda 0, 2026-07-19); (3) 0 inscrições `pushSubscription` (bloqueado pelo elo 1); (4) 74 `Notification` geradas no sino (eventos fluem) mas **zero envios**; (5) banner no OS = passo humano (Android). **Dois defeitos de código corrigidos com evidência:** (a) o SW `/campanha/sw.js` servia `CACHE_NAME "campanha-dev"` em prod — deploys são CLI `vercel build --prebuilt` (git builds ignorados), e a rota `force-static` congelava o buildId no build onde `VERCEL_GIT_COMMIT_SHA`/`VERCEL_DEPLOYMENT_ID` não existem; a rota virou **`force-dynamic`** (lê `VERCEL_DEPLOYMENT_ID`, garantido em runtime) → cache versionado por deploy (unit test pina `dynamic`); (b) **subscribe não idempotente** — segundo toque em "Ativar neste dispositivo" no mesmo device devolvia a mesma subscription do browser e estourava o UNIQUE do `endpoint` (erro falso com o device já ativo); `subscribeCampaignPush` agora faz find-before-create e responde sucesso. **Ferramenta nova:** `pnpm db:check:push-chain` (`scripts/check-push-chain.mjs`, read-only — `PROD_DATABASE_URL` obrigatória, conexões com `default_transaction_read_only`) fecha um veredito por elo (SW servido/versionado, envs, consentimento, inscrições por usuário, log de eventos) com exit code. **Ops:** par VAPID gerado e adicionado em **Production** (`VAPID_PUBLIC_KEY`/`VAPID_PRIVATE_KEY`/`VAPID_SUBJECT`/`NEXT_PUBLIC_VAPID_PUBLIC_KEY`); preview ficou de fora — o projeto não tem Git repo conectado (deploys CLI) e `vercel env add ... preview` exige branch (`branch_not_found`); `NEXT_PUBLIC_*` precisa do build do próximo deploy para inliner. \*\*Pe...
|
||||
**Recently resolved (2026-08-09):** **C106** (Issue #517) — feed de atualizações `/campanha/atualizacoes` sem moldura no mobile: label "Filtrar atualizações" vira sr-only (continua no a11y tree), o filtro perde caixa/borda e fica **sticky** sob a top bar com a linha separadora (`border-bottom`), cards edge-to-edge (`-mx-4`) sem borda/arredondamento com divisor de linha. **Mecanismo herdado do C101** (CSS de página, não prop no chassis): `CampaignUpdatesFeed.css` com media query + `:has()` zerando o padding-top do scroll container (padrão `activity-agenda-filter-strip`); o chassis B127 ganhou só um hook estável `data-slot="campaign-omnibox-field"` (sem mudança de comportamento, reutilizável pelo B184). "Nova atualização" (texto+outline) some do mobile e vira **icon no header via `SetCampaignHeaderAction`** (slot C94/C95; `md:hidden` + botão `hidden md:inline-flex` — gate de resolução 100% CSS, mesmo modal C89). Empty state: copy única "Ajuste o filtro ou registre um novo fato de campo." (descreve a ação, vale nas duas resoluções). **Bug pré-existente corrigido no caminho:** o `@layer base` editorial aplica `my-6 ml-6 list-disc [&>li]:mt-2` a todo `ul` — o feed era a única lista campaign em `<ul>` (indent de 24px + 8px por li; precedente do patch: `[data-theme='campaign'] p { margin-top: 0 }`); a lista neutraliza na própria classe. **Achado registrado:** páginas dinâmicas (searchParams awaitado) têm um nó `#S:0` hidden **transitório** durante o streaming (cópia da página; some em ~1–5s; só no build de produção) — os e2e aguardam o stream assentar (`settleStream`). Sem migration/access/Consent. Intenção [`atualizacoes-mobile-sem-moldura.md`](plans/atualizacoes-mobile-sem-moldura.md); impl [`atualizacoes-mobile-sem-moldura-impl.md`](plans/atualizacoes-mobile-sem-moldura-impl.md).
|
||||
**Recently resolved (2026-08-09):** **D6** (Issue #521) — push no device fechado de ponta a ponta. **Diagnóstico com evidência por elo** (leitura read-only de prod): (1) **envs VAPID ausentes no Vercel production** (verificado com `vercel env ls production`) — elo raiz: sem elas o servidor nunca chama o web-push e o card de perfil desabilita "Ativar"; (2) consentimento `campanha-notificacoes-push` já publicado (Onda 0, 2026-07-19); (3) 0 inscrições `pushSubscription` (bloqueado pelo elo 1); (4) 74 `Notification` geradas no sino (eventos fluem) mas **zero envios**; (5) banner no OS = passo humano (Android). **Dois defeitos de código corrigidos com evidência:** (a) o SW `/campanha/sw.js` servia `CACHE_NAME "campanha-dev"` em prod — deploys são CLI `vercel build --prebuilt` (git builds ignorados), e a rota `force-static` congelava o buildId no build onde `VERCEL_GIT_COMMIT_SHA`/`VERCEL_DEPLOYMENT_ID` não existem; a rota virou **`force-dynamic`** (lê `VERCEL_DEPLOYMENT_ID`, garantido em runtime) → cache versionado por deploy (unit test pina `dynamic`); (b) **subscribe não idempotente** — segundo toque em "Ativar neste dispositivo" no mesmo device devolvia a mesma subscription do browser e estourava o UNIQUE do `endpoint` (erro falso com o device já ativo); `subscribeCampaignPush` agora faz find-before-create e responde sucesso. **Ferramenta nova:** `pnpm db:check:push-chain` (`scripts/check-push-chain.mjs`, read-only — `PROD_DATABASE_URL` obrigatória, conexões com `default_transaction_read_only`) fecha um veredito por elo (SW servido/versionado, envs, consentimento, inscrições por usuário, log de eventos) com exit code. **Ops:** par VAPID gerado e adicionado em **Production** (`VAPID_PUBLIC_KEY`/`VAPID_PRIVATE_KEY`/`VAPID_SUBJECT`/`NEXT_PUBLIC_VAPID_PUBLIC_KEY`); preview ficou de fora — o projeto não tem Git repo conectado (deploys CLI) e `vercel env add ... preview` exige branch (`branch_not_found`); `NEXT_PUBLIC_*` precisa do build do próximo deploy para inliner. **Pendência humana:** teste em device real (Android Chrome) após o deploy — ativar em `/campanha/perfil`, disparar evento, conferir banner + toque; `db:check:push-chain` antes/depois. Sem migration, access ou Consent (fail-closed intacto). Intenção [`push-notificacoes-dispositivo-producao.md`](plans/push-notificacoes-dispositivo-producao.md); impl [`push-notificacoes-dispositivo-producao-impl.md`](plans/push-notificacoes-dispositivo-producao-impl.md).
|
||||
|
||||
**Recently resolved (2026-08-10):** **C106** (Issue #517) — feed de atualizações `/campanha/atualizacoes` sem moldura no mobile: **cards edge-to-edge** (`-mx-4` no ul) sem moldura/arredondamento com uma linha separadora (`border-b last:border-b-0` — padrão exato dos cards do B184) + **empty state com copy única** "Ajuste o filtro ou registre um novo fato de campo." (descreve a ação, vale nas duas resoluções; o texto antigo citava o botão "+ Nova atualização"). O filtro sticky/sem label/moldura e o icon "Nova atualização" no header **foram entregues pelo irmão B184/C107 em `main`** (`campaignListOmniboxFormClassName` + chassis borderless < md + `campaignMobileHeaderIconClassName`, id `campaign-updates-new`) — no rebase, a versão do irmão venceu o conflito em `CampaignUpdatesFilters.tsx` (edit the owner, não twin; a hipótese original de CSS de página no padrão C101 foi descartada na execução). **Bug pré-existente corrigido no caminho:** o `@layer base` editorial aplica `my-6 ml-6 list-disc [&>li]:mt-2` a todo `ul` — o feed era a única lista campaign em `<ul>` (indent de 24px + 8px por li; precedente do patch: `[data-theme='campaign'] p { margin-top: 0 }`); a lista neutraliza na própria classe. **Achado registrado:** páginas dinâmicas (searchParams awaitado) têm um nó `#S:0` hidden **transitório** durante o streaming (cópia da página; some em ~1–5s; só no build de produção) — os e2e aguardam o stream assentar (`settleStream`). E2E novo `tests/e2e/campaignUpdatesMobile.e2e.spec.ts` (mobile: label oculta, form sticky + linha, icon abre o bottom sheet, cards edge-to-edge; empty state; regressão desktop). Sem migration/access/Consent. Intenção [`atualizacoes-mobile-sem-moldura.md`](plans/atualizacoes-mobile-sem-moldura.md); impl [`atualizacoes-mobile-sem-moldura-impl.md`](plans/atualizacoes-mobile-sem-moldura-impl.md).
|
||||
1c6b3d6e (feat(C106): cards do feed edge-to-edge com linha + empty state (padrão B184/C107 compartilhado))
|
||||
|
||||
**Recently resolved (2026-08-09):** **B183** (Issue #501) — o auto-zoom do Safari iOS em inputs do PWA `/campanha` (font < 16px ao focar, escala que não volta no standalone) foi eliminado pela **causa**: uma regra CSS única em `styles.css` — `@media (pointer: coarse) and (hover: none)` + `[data-theme='campaign'] :is(input, select, textarea, [contenteditable='true']) { font-size: 1rem }` — cobrindo omnibox B127, Command search, native-select e textareas em qualquer orientação do iPhone (landscape chega a 932px de largura, o que descartou escopo por `max-width`). Unlayered vence as utilities `text-sm` sem `!important`; desktop (pointer fine) fica intocado; `Input`/`Textarea` do ui já eram `text-base md:text-sm`. Sem migration, access, Consent ou mudança de componente. E2E novo `tests/e2e/campaignIosInputZoom.e2e.spec.ts` pina o contrato: emulação `devices['iPhone 13']` → omnibox de `/campanha/municipios` computa **16px**; control desktop → permanece **14px**. Intenção [`pwa-ios-autozoom-input-foco.md`](plans/pwa-ios-autozoom-input-foco.md); impl [`pwa-ios-autozoom-input-foco-impl.md`](plans/pwa-ios-autozoom-input-foco-impl.md).
|
||||
f37b8bcd (feat(C106): atualizações mobile sem moldura — omnibox sticky, criar no header, cards edge-to-edge)
|
||||
|
||||
**Recently resolved (2026-08-10):** **B185** (Issue #524) — o Sollinha ganhou a tool **`getPendingLeaderships`** (`src/utilities/ai/tools/getPendingLeaderships.ts`): "quais lideranças ainda precisam ser abordadas" por **território de identidade** (grafia tolerante a acento — "Vale do Jiquiriça" resolve para a região canônica), **cidade** ("Salvador" = as 19 ZE juntas) ou **município** (aliases canônicos), com o **critério de pendência sempre declarado na resposta** (`'A abordar'/'Em disputa', ou 'Engajado' sem compromisso de votos no escopo consultado` — eixo do compromisso = presença de `votePledge` liderança×município no escopo; `negativo` é excluído na query, fail-closed), lista com nome/municípios/status/última atualização/**assessores responsáveis** (nomes resolvidos em query própria — nunca `depth` populando `campaignUser`), top N (default 20, max 50) com `total` e `truncado`, escopo omitido = escopo de acesso do usuário. Filtro **C3** `sem_assessor` (`advisors: { exists: false }`, precedente B176) e modo **C4** `municipios_sem_lideranca` (municípios do escopo sem nenhuma liderança). **Gate staff inline** no topo do `execute` (leader → `{ error: 'Leitura de dados de lideranças negada.' }` antes de qualquer query, mesmo shape da B180; 1 call site — sem helper); leituras todas `overrideAccess: false, user: ctx.user` (RBAC atual). Links via `buildCampaignLinks` existente (nada mudou lá); seção nova no system prompt manda declarar o critério. Unit tests novos (`pendingLeadershipsTool.unit.spec.ts`, 14) — gate fail-closed com payload intocado, critério por status+pledge, pledge fora do escopo não satisfaz (where `municipality in`), escopos com acento/Salvador/município/erro, `sem_assessor` no where, C4, truncamento, nomes de assessores; allowlist na convenção P3-D justificada (filtro de domínio sobre set resolvido ≠ escopo de actor). Sem migration, access change ou Consent. Intenção [`sollinha-liderancas-pendentes-abordagem.md`](plans/sollinha-liderancas-pendentes-abordagem.md); impl [`sollinha-liderancas-pendentes-abordagem-impl.md`](plans/sollinha-liderancas-pendentes-abordagem-impl.md).
|
||||
|
||||
**Recently resolved (2026-08-09):** **C104** (Issue #505) — compromissos **"Todo o dia"** na agenda: o sheet de criação rápida (C91) e o formulário completo ganharam o toggle **Todo o dia** (checkbox; no sheet entre o título e Início/Término, no form no topo do card "Data e horário") — ligado, Início e Término viram **só datas** (término pode ser outro dia = faixa de vários dias inteiros; dia único = `startAt === endAt`). Representação: campo novo `allDay` (migration `20260810_010844_add_activity_all_day`) + convenção de instantes **fim inclusivo** (startAt = 1º dia 00:00 America/Bahia, endAt = último dia 00:00; Bahia sem DST); conversões exclusivo↔inclusivo (FullCalendar/iCal usam fim exclusivo) concentradas no módulo puro `lib/activityAllDay.ts` (unit-pinado: dia único, multi-dia, virada de mês/ano, rótulo "10/08/2026 a 12/08/2026"). Calendário: `allDaySlot` ligado (faixa no topo de semana/dia), `toEventInput` com `allDay`, reschedule converte os `startStr`/`endStr` exclusivos e envia `allDay`; **guard de drop**: arrastar entre a lane all-day e a grade de horário é rejeitado (revert + toast — converter por drag é feature fora do escopo). "Mais detalhes" preserva a escolha (`allDay=1` + datas civis nos params; form nasce com toggle ligado). Rótulos all-day em card, overview, dossiê do município, cabeçalho de detalhe e home search; feed iCal exporta `DTSTART;VALUE=DATE`/`DTEND;VALUE=DATE` com fim exclusivo. Liderança não consegue flipar `allDay` (snapshot staff). Sem access/Consent. Intenção [`agenda-toggle-todo-o-dia.md`](plans/agenda-toggle-todo-o-dia.md); impl [`agenda-toggle-todo-o-dia-impl.md`](plans/agenda-toggle-todo-o-dia-impl.md).
|
||||
|
||||
**Recently resolved (2026-08-09):** **D6** (Issue #521) — push no device fechado de ponta a ponta. **Diagnóstico com evidência por elo** (leitura read-only de prod): (1) **envs VAPID ausentes no Vercel production** (verificado com `vercel env ls production`) — elo raiz: sem elas o servidor nunca chama o web-push e o card de perfil desabilita "Ativar"; (2) consentimento `campanha-notificacoes-push` já publicado (Onda 0, 2026-07-19); (3) 0 inscrições `pushSubscription` (bloqueado pelo elo 1); (4) 74 `Notification` geradas no sino (eventos fluem) mas **zero envios**; (5) banner no OS = passo humano (Android). **Dois defeitos de código corrigidos com evidência:** (a) o SW `/campanha/sw.js` servia `CACHE_NAME "campanha-dev"` em prod — deploys são CLI `vercel build --prebuilt` (git builds ignorados), e a rota `force-static` congelava o buildId no build onde `VERCEL_GIT_COMMIT_SHA`/`VERCEL_DEPLOYMENT_ID` não existem; a rota virou **`force-dynamic`** (lê `VERCEL_DEPLOYMENT_ID`, garantido em runtime) → cache versionado por deploy (unit test pina `dynamic`); (b) **subscribe não idempotente** — segundo toque em "Ativar neste dispositivo" no mesmo device devolvia a mesma subscription do browser e estourava o UNIQUE do `endpoint` (erro falso com o device já ativo); `subscribeCampaignPush` agora faz find-before-create e responde sucesso. **Ferramenta nova:** `pnpm db:check:push-chain` (`scripts/check-push-chain.mjs`, read-only — `PROD_DATABASE_URL` obrigatória, conexões com `default_transaction_read_only`) fecha um veredito por elo (SW servido/versionado, envs, consentimento, inscrições por usuário, log de eventos) com exit code. **Ops:** par VAPID gerado e adicionado em **Production** (`VAPID_PUBLIC_KEY`/`VAPID_PRIVATE_KEY`/`VAPID_SUBJECT`/`NEXT_PUBLIC_VAPID_PUBLIC_KEY`); preview ficou de fora — o projeto não tem Git repo conectado (deploys CLI) e `vercel env add ... preview` exige branch (`branch_not_found`); `NEXT_PUBLIC_*` precisa do build do próximo deploy para inliner. \*\*Pe... (line truncated to 2000 chars)
|
||||
**Recently resolved (2026-08-09):** **C102** (Issue #498) — no mobile (<768px), nenhuma tela `/campanha` de staff mostra mais hamburger nem sheet de sidebar: a navegação staff mora na barra inferior + drawer "Mais". `CampaignMobileTopBar` esconde o `SidebarTrigger` via `useCampaignPageChromeRole` + `isStaffCampaignRole` (leader mantém — lockdown sem barra inferior); `CampaignSidebar` retorna `null` quando `isMobile && staff`, desmontando o Sheet; **B18 (filtros salvos de Municípios) migrou para o drawer "Mais"** — `MunicipalityNavSavedFilters` ganhou `variant: 'overflow'` (mesma store `useMunicipalitySavedFilters`, mesma lógica apagar/desfazer/sucessão de foco; no drawer o fallback de foco vira o link Perfil do footer) e `CampaignBottomNav` passou a renderizá-la entre destinos e footer (container com `overflow-y-auto`). **Bug pré-existente corrigido no caminho (D4):** o `<Toaster>` vivia dentro do wrapper `[contain:layout_paint]` do painel da AI — `contain: paint` vira containing block para `position: fixed` e cria stacking context próprio, prendendo o toast (z 999999999 do sonner) ABAIXO dos portais z-50 de drawer/sheet: qualquer toast com ação (ex. "Desfazer") era inalcançável com modal aberto; o Toaster foi movido para o root layout `(campaign)/layout.tsx` (irmão do `{children}`, direto no `<body>`). Testes: 2 unit novos na top bar (staff sem trigger / leader com trigger), 3 e2e novos (staff mobile sem trigger e sem dialog Sidebar; leader abre o sheet com "Meus contatos"; fluxo completo salvar→navegar→apagar→desfazer no drawer). Sem migration, access ou Consent. Intenção [`c102-mobile-sem-botao-sidebar.md`](plans/c102-mobile-sem-botao-sidebar.md); impl [`c102-mobile-sem-botao-sidebar-impl.md`](plans/c102-mobile-sem-botao-sidebar-impl.md).
|
||||
|
||||
**Recently resolved (2026-08-09):** **B179** (Issue #462) — o Sollinha passou a falar de si **no masculino**: o system prompt (`src/utilities/ai/systemPrompt.ts`) abre com "Você é **o** Sollinha" e ganhou regra explícita (auto-referência masculina em primeira pessoa, nunca flexões femininas sobre si) — o welcome da UI já era masculino; o placeholder do chat virou "Pergunte para o Sollinha..." (`CampaignAIChat.tsx`) com os seletores e2e acompanhando (2 specs). Sem migration, access, Consent ou guarda automatizada (decisão do gate: só édito de texto). Os planos entregues da família (B162/B166/B167/B173/B174/B177) permanecem frozen com "a Sollinha" histórico — o que vale é a voz no runtime e o que se escreve daqui pra frente. Intenção [`sollinha-genero-masculino.md`](plans/sollinha-genero-masculino.md); impl [`sollinha-genero-masculino-impl.md`](plans/sollinha-genero-masculino-impl.md).
|
||||
|
||||
|
|
|
|||
83
docs/plans/restaurar-entradas-changelog-b183-c102-impl.md
Normal file
83
docs/plans/restaurar-entradas-changelog-b183-c102-impl.md
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
# Impl: Restaurar entradas B183/C102 perdidas do docs/CHANGELOG-AGENTS.md
|
||||
|
||||
Status: aprovado (gate humano 2026-08-10)
|
||||
Atualizado em: 2026-08-10
|
||||
Issue: #557
|
||||
Intenção: docs/plans/restaurar-entradas-changelog-b183-c102.md
|
||||
Appetite restante: ~0,25 dia eng (herdado; exploração já consumida, execução é minutos)
|
||||
|
||||
## Leitura da intenção
|
||||
|
||||
- **Outcome:** as entradas de entrega perdidas do CHANGELOG voltam ao main, sem duplicar nem alterar texto (fonte: git), na posição cronológica correta; nada mais é tocado; sem Issue nova por entrada.
|
||||
- **O que NÃO negociar:** texto canônico vindo do git (`8c79eddf`); posição relativa de C102 (após C104, antes de B179 — mesma ordem de `8c79eddf`); nenhuma outra **entrada legítima** é editada/removida; sem guarda automatizada de presença.
|
||||
- **O que reavaliar:** a hipótese da intenção ("só B183 e C102 sumiram") está **desatualizada** — o snapshot da intenção (2026-08-10, pré-merges do B184/C103/C106/B185) não viu o churn do rebase do C106 (PR #555), que (a) **perdeu também a entrada da C108** (escrita em `c3f10cce`, ausente em main) e (b) deixou lixo de resolução de conflito no topo: D6 duplicado, C106 duplicado e 2 linhas de `git log` vazadas no markdown. A B183, que a intenção manda restaurar, **já foi re-adicionada** pela branch da C106 (`7eaa65ce`, PR #555 — `fab834fc`/B184 não a tocou), byte-idêntica à fonte — restaurá-la de novo criaria duplicata. E o rebase do C104 (`ea700e31`) **truncou a entrada da D6** (perdeu o final "Pendência humana: …"; o prettier `d52d0016` escapou `**Pe` → `\*\*Pe`) — achado dos revisores do /simplify, corrigido na mesma sessão (fase 2).
|
||||
|
||||
## Abordagem recomendada
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[Inventário verificado no git] --> B[C102 restaurada de 8c79eddf no lugar do D6 duplicado]
|
||||
A --> C[C108 restaurada de c3f10cce no topo da seção]
|
||||
A --> D[D6 duplicado removido<br/>C106 v1 removida<br/>2 linhas git vazadas removidas]
|
||||
A --> E[B183: verificar presente e idêntica - sem ação]
|
||||
D --> F[git diff: só as mudanças esperadas]
|
||||
F --> G[grep de sanidade + format:check + gate:fast]
|
||||
G --> H[commit + pnpm push + PR Closes #557]
|
||||
```
|
||||
|
||||
**Opções consideradas:** A | B | C
|
||||
**Recomendação:** A — restauração cirúrgica das 2 entradas perdidas (C102 + C108) + remoção do lixo do mesmo churn (dup D6 no lugar da C102, dup C106 v1, 2 linhas vazadas). É a única opção que deixa a seção íntegra: uma entrada por entrega, sem texto alterado, sem conteúdo canônico perdido.
|
||||
**Rejeitadas:**
|
||||
|
||||
- B — executar a intenção ao pé da letra (restaurar só C102): deixa C108 perdida, D6 duplicado, C106 duplicado e linhas de commit vazadas como defeito permanente num doc que agentes leem para contexto. A intenção não previu o churn posterior; "nenhuma outra entrada é tocada" refere-se a entradas legítimas, não a lixo de conflito.
|
||||
- C — reordenar a seção topo inteira pela ordem de merges: viola o "não reorganizar o arquivo" da intenção e mexe em entradas legítimas (B184/C103/B185…). O custo (diff grande, risco de desordenar o que está aceitável) não compra nada para o aceite.
|
||||
- D — registrar Issues novas para as entregas mergeadas que **nunca** escreveram entrada (B187/B188/B190/B191/C107/C105 — verificado: branch tips e merges não tocaram o CHANGELOG): proibido pela intenção ("Sem Issue nova por entrada"); é gap de processo, não perda. Registrado como nota no impl e levado ao capture-review-debts se o humano quiser.
|
||||
|
||||
### Componentes / mudanças
|
||||
|
||||
- **`docs/CHANGELOG-AGENTS.md`** (único arquivo): edição de ~5 linhas no topo da seção "Recently resolved".
|
||||
1. **C102** — linha inteira de `8c79eddf` (linha 11), colada verbatim, no lugar do D6 duplicado (atual linha 23, entre C104 e B179). `git diff` contra o arquivo da intenção confirma texto idêntico.
|
||||
2. **C108** — linha inteira de `c3f10cce` (linha 7), colada verbatim, no **topo da seção** (acima da B184): era a posição dela quando escrita (mais nova na época) e é a posição menos ambígua para uma entrada restaurada; datada 2026-08-10 como a B184.
|
||||
3. **D6 duplicado** (linha 11 vs 23) — o da linha 23 é substituído pela C102; o da linha 11 (posição canônica) permanece → D6 único.
|
||||
4. **C106 duplicado** (linhas 12–13) — remove a v1 (2026-08-09, rascunho pré-rebase; a própria v2 a descreve como superada: "a hipótese original de CSS de página … foi descartada na execução"); mantém a v2 (2026-08-10, texto final reconciliado, com E2E).
|
||||
5. **Linhas vazadas** — `1c6b3d6e (…)` e `f37b8bcd (…)` (saídas cruas de `git log --oneline` coladas no markdown) — removidas.
|
||||
6. **B183** — verificação apenas: presente na linha 16 e byte-idêntica à fonte (já demonstrado: linha de contexto no diff `8c79eddf→main`). Nenhuma ação.
|
||||
- **Migration:** sem migration.
|
||||
- **Access / Consent:** não se aplica.
|
||||
- **UI:** não se aplica (docs-only; CI `build-affected` pula o build).
|
||||
|
||||
### Dados → forma (se aplicável)
|
||||
|
||||
Não se aplica (sem dados/forma).
|
||||
|
||||
## Fases verificáveis
|
||||
|
||||
1. **Fonte + colagem** — extrair as 2 linhas canônicas com `git show` (C102 de `8c79eddf:…`; C108 de `c3f10cce:…`), colar verbatim (nunca redigitar — evita drift de transcrição).
|
||||
2. **Edição cirúrgica** — aplicar os 5 pontos acima no arquivo; `git diff` deve mostrar: +2 linhas de entrada (C102, C108), −1 entrada (C106 v1), −2 linhas vazadas, −1 D6 duplicado (substituído pela C102). Nenhuma outra linha muda.
|
||||
3. **Sanidade** — `grep -c "C102\|C108"` = 2 em posições esperadas; `grep -c "D6"` = 1; `grep -c "C106"` = 1; zero linhas casando `^[0-9a-f]{7,40} (`; `git show 8c79eddf` diffs das 2 entradas restauradas = vazio; `pnpm format:check`; `pnpm gate:fast`.
|
||||
4. **Entrega** — commit com o impl plan incluso; `pnpm push -u origin HEAD`; PR Ready `--base main` + `Closes #557` + auto-merge; `gh pr checks --watch --required`.
|
||||
|
||||
## Rabbit holes / Não escopo (engenharia)
|
||||
|
||||
- Não criar guarda automatizada de presença de entradas no CHANGELOG (intenção; processo = revisar diff em merges que o toquem).
|
||||
- Não reordenar a seção nem reorganizar o arquivo.
|
||||
- Não restaurar C107/B187/B188/B190/B191/C105 (nunca escritas — gap de processo; fora do aceite). B186/B189 não mergeadas — entradas vêm com os merges.
|
||||
- Não criar Issue por entrada nem editar outras Issues in-progress.
|
||||
|
||||
## Riscos e mitigação
|
||||
|
||||
- **Drift de transcrição na colagem** → colagem via `git show | sed -n` com verificação de diff (fase 1 e 3); nunca redigitar.
|
||||
- **Conflito com merge em andamento** (B186/B189 locais não mergeados também contêm c3f10cce) → `pnpm push` + rebase na branch antes do PR se necessário; o fix é no arquivo, conflito resolve-se a favor da versão restaurada.
|
||||
- **gate:fast lento** (docs-only muda nada) → rodar mesmo assim (exigência da skill); esperado green em lint/typecheck/unit.
|
||||
|
||||
## Aceite de engenharia
|
||||
|
||||
- [x] Aceite de produto da intenção ainda coberto (C102/C108 restauradas; B183 já presente e idêntica; texto canônico intacto)
|
||||
- [x] Invariantes AGENTS/engineering-standards (docs-only; sem migration/access/Consent/DB)
|
||||
- [x] Testes de domínio previstos: nenhum (docs); gate:fast + grep de sanidade + diff verificado
|
||||
|
||||
---
|
||||
|
||||
### Nota de achado (gap de processo, fora do escopo)
|
||||
|
||||
Entregas mergeadas sem entrada no CHANGELOG (verificado em branch tips e merges): B187 (#559), B188 (#548), B190 (#560), B191 (#554), C107 (#552), C105 (#536). B186 e B189 seguem **não mergeadas** em branch (a B189 escreveu entrada no tip da branch em 2026-08-10 — virá junto com o merge; a B186 ainda não tem). Recomendação de processo (não automatizada): revisar o diff do CHANGELOG no rebase de cada branch que o toque — o mesmo processo que a intenção já registra.
|
||||
Loading…
Reference in a new issue