chore: migrate .cursor/ references to .agents/ folder
Replace all project-local .cursor/ path references with .agents/ across rules, skills, environment config, hooks, and ignore files. Keep Cursor editor paths (~/.cursor/, window.cursor, CURSOR_API_KEY) and vendored Impeccable editor-hook paths unchanged.
This commit is contained in:
parent
781360bcf9
commit
896d957497
57 changed files with 101 additions and 100 deletions
|
|
@ -38,4 +38,4 @@ Defeso desde 04/07 (transferência voluntária vedada; empenhar pode); inaugura
|
|||
- Roteiro da sessão real: `docs/research/roteiro-entrevista-emendas-responsavel-real.md`
|
||||
- Fichas: `persona-emendas-parlamentar.md` · `persona-emendas-assessor-orcamento.md` · `persona-emendas-coordenador-comunicacao.md` · `persona-emendas-coordenador-campanha.md` (anexo [R] = extrato da sessão real 2026-07-23)
|
||||
- Evidência real de campo: `docs/CUSTOMER.md` (Interview Snapshot 2026-07-23 — O6 dossiê pré-agenda com "emendas aportadas", caso Nazaré das Farinhas)
|
||||
- Precedente metodológico: ciclos 1–2 em `docs/research/README.md`; notebook irmão `.cursor/rules/projects/financas-campanha.mdc`
|
||||
- Precedente metodológico: ciclos 1–2 em `docs/research/README.md`; notebook irmão `.agents/rules/projects/financas-campanha.mdc`
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ alwaysApply: false
|
|||
|
||||
# Núcleos Eleitorais → Municípios
|
||||
|
||||
**Como ler este notebook:** as entradas "**entregue em código**", decisões de sessão e micro-escolhas de implementação abaixo são **changelog** (o que aconteceu e onde está o plano). Não são locks. Não impeçam editar o código que uma entrega anterior criou; não obriguem a espelhar um twin em vez de mudar o dono. Constraints reais de produto/segurança vivem em `AGENTS.md`, `docs/ARCHITECTURE.md` e `.cursor/rules/engineering-standards.mdc`. Para o estado vivo da fila, use Issues + `project-status` — não trate este arquivo como fonte canônica de "o que ainda pode mudar".
|
||||
**Como ler este notebook:** as entradas "**entregue em código**", decisões de sessão e micro-escolhas de implementação abaixo são **changelog** (o que aconteceu e onde está o plano). Não são locks. Não impeçam editar o código que uma entrega anterior criou; não obriguem a espelhar um twin em vez de mudar o dono. Constraints reais de produto/segurança vivem em `AGENTS.md`, `docs/ARCHITECTURE.md` e `.agents/rules/engineering-standards.mdc`. Para o estado vivo da fila, use Issues + `project-status` — não trate este arquivo como fonte canônica de "o que ainda pode mudar".
|
||||
|
||||
## Status
|
||||
|
||||
|
|
@ -110,7 +110,7 @@ alwaysApply: false
|
|||
- **B28 entregue em código (2026-07-26):** e-mail + celular na lista `/campanha/liderancas` — colunas **E-mail** e **Celular** (copy-on-click, toast, "—" vazio) mais uma coluna de **Ações** com botão WhatsApp (`wa.me`, desabilitado com `aria-label` honesto sem celular válido), ordem final Nome → E-mail → Celular → Status → Municípios → Organizações → Acesso ao app → Ações, no mesmo padrão visual/interativo de `/campanha/assessores` (**B19 ✓**). `whatsAppHrefForPhone` promovido de `AdvisorsTable.tsx` para `src/lib/phone.ts` (pura, client-safe); novo `shared/CampaignCopyableCell.tsx` (+ `campaignReadCellClassName` exportado) nasce **já no 2º call site** — `AdvisorsTable.tsx` migrado no mesmo PR para consumi-lo, eliminando o `copyText`/`READ_CELL_CLASS` duplicados. `leadershipData.ts`: `contactNameAndPhone` virou `contactSummary` (+ `email`), `LeadershipRowViewModel.email` populado sem query nova (`depth: 1` já trazia o `Contact` inteiro), e `loadLeadershipDetail` parou de reparsear `doc.contact` — reusa `row.email` de `toLeadershipRows`. Sem migration/collection/Consent/URL novo; access inalterado. Gate verde: tsc/lint/format/check:cycles limpos, 393 unit+int, build produção ok; `pnpm exec knip` mantém o erro pré-existente ao carregar `payload.config.ts` (P3, não relacionado); `pnpm test:e2e` reproduziu só o flake pré-existente já ledgerado em `campaignMunicipalities.e2e.spec.ts` (checkbox de consentimento do `LeaderContactsPanel` antes da hidratação) — nenhuma rota tocada por este item falhou. Aikido 0 achados nos 5 arquivos novos/editados. Plano: [`email-celular-lista-liderancas.md`](../../../docs/plans/email-celular-lista-liderancas.md).
|
||||
- **Fill-in "Cobertura da meta" → "Cobertura" entregue em código (2026-07-28):** coluna `goalCoverage` e sort `deficit` em `/campanha/municipios` passam a mostrar **"Cobertura"** via SSoT pós-B17 (`municipalityListSortLabels.deficit` → `municipalityColumnLabels.goalCoverage`); `<dt>` do card mobile cita o mesmo registro (sem literal). B22 ✓ mantém a definição longa no hover; título E18, strips, Conta da cadeira e coluna de territórios seguem "Cobertura da meta". Pins em `campaignComponents.unit.spec.ts` e `municipalityList.unit.spec.ts`. Sem migration. Plano as-built: [`renomear-coluna-cobertura-meta.md`](../../../docs/plans/renomear-coluna-cobertura-meta.md).
|
||||
- **Fill-in registrado (2026-07-25):** remover coluna "Tipo" de `/campanha/municipios` — município e ZE tratados iguais na coordenação; filtrar ZE = filtrar Salvador (19 slugs). Remove coluna + filtro/sort UI + `?kind=` do contrato URL; schema/catálogo `kind` intacto (mapa, B8, dossiê). Appetite ~0,25–0,5d; Janela 1; cortável; Impeccable B. Plano: [`remover-coluna-tipo-municipios.md`](../../../docs/plans/remover-coluna-tipo-municipios.md).
|
||||
- **Pass 2 — Consolidação de engenharia entregue (2026-07-25, W0–W5 + D3):** tudo que foi one-shotted desde o Pass 1 virou infraestrutura compartilhada e arquitetura documentada. **W1 sistema de listas:** colunas como dado em `shared/CampaignTable.tsx` (seams `mandatory`/`defaultVisible` deixam **B17 trivial**; serialização canônica congelada deixa **B18 trivial**), o god module `municipalityUi.ts` (765 linhas/59 exports) dividido em `municipalityListUrl`/`municipalityListFilters`/`municipalityLabels`/`municipalitySignal`, 8 superfícies migradas com URLs byte-idênticas (pins do W0 verdes) e **B16+ absorvido** (`useOptimistic` no popover, facet por slugs, hrefs via serializador canônico com pin de byte-igualdade, facets no mesmo `Promise.all`); fora por decisão D5: planos (cards), `TerritoryOverviewTable`, comparação, LeaderContacts, preview de import. **W2 fronteiras:** `slug`/`phone`/`wordStartFilter`/`voteEstimate` → `lib/`, chaves de consent em `lib/campaignConsentKeys.ts`, 21 loaders `server-only`, `lib/campaignRoles.ts` client-safe (sidebar sem o barrel), `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 (`utilities/` adiado com gatilho: 3º módulo novo de um domínio num mês). **W4a:** `electionInsights.ts` (941 linhas, 2 exports vivos) **deletado** — sobreviventes em `electionFormat.ts`/`voteTrend.ts`; **E10 nasce em módulo novo**. **W4b:** knip `exports`/`types`/`enumMembers` em **ERROR** no CI, 0 findings (kit ui sem peças mortas; `duplicates` off — únicos hits eram os 6 aliases deliberados `canUpdateX = canReadX`). **W4c:** tabs de detalhe extraídas + factory `detailTabUi`. **W4d:** `runCampaignFormAction` fecha o C8 F4 (13 ações em 7 arquivos; exceções comentadas). **W4e:** tipos de fonte única (cenários, trend, strategy VM nomeado). **W4f:** copy Praça→Município varrida (~70 strings; apoiadores desambiguado: cidade do contato = "Cidade"). **D3:** `submitWhatsapp` resolve `Consent.key='whatsapp-inscricao'` fail-closed; migration `20260725_170000` tagueia o doc vivo — **revisar o SQL antes de push/deploy**. Artefatos novos: `docs/ARCHITECTURE.md` + `.cursor/rules/codebase-map.mdc` (atualizados no mesmo PR que mover coisas). Suites: 46 unit / 48 int / 7 e2e; gates verdes por entrega. Tracker: [`IMPROVE-CODE-QUALITY-PLAN.md`](../../../docs/IMPROVE-CODE-QUALITY-PLAN.md) § Pass 2.
|
||||
- **Pass 2 — Consolidação de engenharia entregue (2026-07-25, W0–W5 + D3):** tudo que foi one-shotted desde o Pass 1 virou infraestrutura compartilhada e arquitetura documentada. **W1 sistema de listas:** colunas como dado em `shared/CampaignTable.tsx` (seams `mandatory`/`defaultVisible` deixam **B17 trivial**; serialização canônica congelada deixa **B18 trivial**), o god module `municipalityUi.ts` (765 linhas/59 exports) dividido em `municipalityListUrl`/`municipalityListFilters`/`municipalityLabels`/`municipalitySignal`, 8 superfícies migradas com URLs byte-idênticas (pins do W0 verdes) e **B16+ absorvido** (`useOptimistic` no popover, facet por slugs, hrefs via serializador canônico com pin de byte-igualdade, facets no mesmo `Promise.all`); fora por decisão D5: planos (cards), `TerritoryOverviewTable`, comparação, LeaderContacts, preview de import. **W2 fronteiras:** `slug`/`phone`/`wordStartFilter`/`voteEstimate` → `lib/`, chaves de consent em `lib/campaignConsentKeys.ts`, 21 loaders `server-only`, `lib/campaignRoles.ts` client-safe (sidebar sem o barrel), `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 (`utilities/` adiado com gatilho: 3º módulo novo de um domínio num mês). **W4a:** `electionInsights.ts` (941 linhas, 2 exports vivos) **deletado** — sobreviventes em `electionFormat.ts`/`voteTrend.ts`; **E10 nasce em módulo novo**. **W4b:** knip `exports`/`types`/`enumMembers` em **ERROR** no CI, 0 findings (kit ui sem peças mortas; `duplicates` off — únicos hits eram os 6 aliases deliberados `canUpdateX = canReadX`). **W4c:** tabs de detalhe extraídas + factory `detailTabUi`. **W4d:** `runCampaignFormAction` fecha o C8 F4 (13 ações em 7 arquivos; exceções comentadas). **W4e:** tipos de fonte única (cenários, trend, strategy VM nomeado). **W4f:** copy Praça→Município varrida (~70 strings; apoiadores desambiguado: cidade do contato = "Cidade"). **D3:** `submitWhatsapp` resolve `Consent.key='whatsapp-inscricao'` fail-closed; migration `20260725_170000` tagueia o doc vivo — **revisar o SQL antes de push/deploy**. Artefatos novos: `docs/ARCHITECTURE.md` + `.agents/rules/codebase-map.mdc` (atualizados no mesmo PR que mover coisas). Suites: 46 unit / 48 int / 7 e2e; gates verdes por entrega. Tracker: [`IMPROVE-CODE-QUALITY-PLAN.md`](../../../docs/IMPROVE-CODE-QUALITY-PLAN.md) § Pass 2.
|
||||
- **Correções e débitos pós-B16 (2026-07-25):** a revisão paralela achou três defeitos funcionais, **corrigidos na própria entrega**: as facetas omitiam só o param multi, então "Prioritária" escondia os não-prioritários do popover de Município e "Sem assessor" esvaziava o de Assessores (cada faceta passou a omitir o grupo do seu popover — `slugs`+`priority`, `advisors`+`coverage`, com int test); "todas as tendências" tinha duas codificações (as três marcadas deixavam `trend=` inútil na URL com o funil inativo — agora `parseMunicipalityListParams` canonicaliza o conjunto completo para ausente e `narrowingMunicipalityTrends` foi deletado); e o Território havia sumido do mobile ao virar multi (voltou como `MobileMultiFilterField` alimentado pela faceta, via novo prop `regionFilterOptions`). O `/simplify` da entrega (quality / performance / reuse em paralelo) aplicou o cleanup barato no próprio branch — setter único sobre params crus em `municipalityUi.ts` (fim de três casts e da escada de `if`), resumo de filtros de três funções para uma, remoção do array `municipalitySlugFilterOptions` (435 objetos que iam no bundle sem leitor), linha de opção única no Popover, facetas reusando o escopo já carregado e `getEligibleAdvisorOptions` de volta a coordenador-only. O que sobrou é maior que cleanup e virou o fill-in **B16+**: `useOptimistic` no lugar do par `{baseKey,next}` manual, payload dos rótulos de município (~20 KB por navegação) e hrefs do Popover a partir de uma base `URLSearchParams` em vez de duas serializações por opção — [`escala-dry-pos-b16.md`](../../../docs/plans/escala-dry-pos-b16.md). Adiados com gatilho no plano: gêmeo `MunicipalityFilterHead` (3º header com filtro), `ui/Command` no Popover (2º popover de busca), predicado de busca unificado, multi-seleção mobile honesta. Fora do `/campanha`: o `next build` inteiro morre quando o global `metadata` vem vazio (`/abaixo-assinado/[id]` chama `stripTrailingSlash` no `undefined`) — registrado em "Site público" no roadmap.
|
||||
- **B16 entregue em código (2026-07-25):** filtros no header das colunas em `/campanha/municipios` — funil + Popover (`MunicipalityHeaderFilter`) ao lado do sort do B15, com multi-seleção OR em Território (`region`), Município (`slug`, com busca acento-insensível e o check "Prioritária" no mesmo popover), Assessores (`advisor`, que também hospeda o toggle com/sem assessor) e Tendência (`trend`); "Limpar" nos multi grandes; mobile mantém os selects empilhados. Header sticky resolvendo contra o scroller do `<main>` (sem scroller interno na tabela) e empty state que troca só as linhas de conteúdo — visão geral e linha de filtros continuam montadas, senão o usuário fica preso em zero resultados. Facetas cross-filtradas (as opções de um filtro respeitam os demais, mantendo o que já está selecionado visível) reaproveitando o escopo já carregado em `loadMunicipalityListFilterFacets`. A pedido do usuário, a coluna "Assessoria" saiu: a ordenação `coverage` passou para "Assessores", o filtro com/sem assessor virou opção do popover, e o alerta "sem responsável" do E9 (prioridade alta sem ninguém) migrou para a célula de assessores, onde antes só haveria um "Sem assessor" apagado. Plano: [`filtros-no-header-lista-municipios.md`](../../../docs/plans/filtros-no-header-lista-municipios.md).
|
||||
- **E16 entregue em código (2026-07-25):** Dossiê do município (pré-agenda) — aba `?tab=dossie` no detalhe (`MunicipalityDossier.tsx`, server component em Suspense) compondo os loaders existentes via `municipalityDossierData.ts` (baseline TSE + rank A11, conta da cadeira E8, pledges, rede de lideranças com frescor `updatedAt`, agenda `actionPlan` `overrideAccess: false`, sinais C12, perfil IBGE A8 com caveat para zonas — reentrada do artefato órfão); caps 8 lideranças / 5 sinais / 3+2 planos com "ver tudo" por seção; novo campo staff-only `municipality.budgetNotes` ("Emendas aportadas", G11 manual-first) via migration `20260725_022155_add_municipality_budget_notes` (o `.json` da migration também sara a cadeia de snapshots pós-`campaign_goals`); form de estratégia + zod + view model estendidos; **print CSS** (chrome `print:hidden`, shells `print:h-auto print:overflow-visible`, tipografia A4 em `styles.css`) — dossiê imprime 1–2 páginas com capa autocontida ("Gerado em"). Int test `municipalityDossierData.int.spec.ts` (mock do `unstable_cache` do baseline). Gate verde (tsc/lint/knip/363 tests/build); Aikido bloqueado por sessão expirada (re-login navegador pendente). Plano: [`dossie-municipio.md`](../../../docs/plans/dossie-municipio.md).
|
||||
|
|
@ -130,7 +130,7 @@ alwaysApply: false
|
|||
- **E4R entregue em código + seed em produção (2026-07-24):** `pnpm db:seed:projecao` (`scripts/import-projecao.mjs` + `src/lib/projectionSheetParse.ts`) importa MAPA GERAL canônico → `expectedVotes` (Bom→otimista, Regular→média, Mínimo→pessimista) + `priority` com **overwrite-always**; Salvador pulado; zero PII. No mesmo dia o grupo duplicado `voteGoals` foi removido do app (ver Decisões). Seed local e **produção Neon** (2026-07-24): arquivo canônico `docs/sheets/Mapa projeção de votos Solla 2026.xlsx` (+ referência `Mapa_projecao_votos_Solla_2026.xlsx` só A×B), **189** municípios atualizados, **50** `priority=alta`, Salvador pulado, re-dry-run pós-apply **delta=0**. Plano: [`import-planilha-projecao.md`](../../../docs/plans/import-planilha-projecao.md).
|
||||
- **Sync roadmap × sessão de campo (2026-07-24):** os achados da sessão real do CG (2026-07-23, `docs/CUSTOMER.md`) foram incorporados ao roadmap e aos planos de inteligência — âncora da mesa = **% da própria votação** (A11 entrega a lente; E9/E10/B13 expõem ao lado de LQ/captura); piso 150 mil resolve a meta inicial de E8; O6 vira **E16 dossiê do município** + gap **G11 emendas por município**; O7 confirma C12 não cortável; E13 rebaixado na fila de corte ("perna" é a restrição dominante); gatilho de D3 reformulado (deltas do ZAP não absorvidos pelo fluxo sede-digita/C12); FD2 absorvido por R6; O8 "ilhas isoladas" em A validar. **Decisão de produto: E4 reaberto como E4R** — seed único via script das planilhas de `docs/sheets/` (arquivo com espaços = canônico de estratégia; underscore = referência Salvador; v1 só `expectedVotes`/`priority`, sem PII; Salvador pulado com relatório). Novos itens: **E4R** (janela 1, não cortável), **A11**, **E17 tabela TI no Início** (pedido do candidato; primeira fatia de E12), **B14 município mais próximo** (geolocalização → atalho no Início staff; prompt 1×/sessão; client-only), **B15 ordenar lista por coluna**. Planos novos: `import-planilha-projecao.md`, `ranking-votos-municipio.md`, `tabela-ti-inicio.md`, `dossie-municipio.md`, `municipio-mais-proximo.md`, `ordenacao-colunas-lista-municipios.md`, `cenario-junto-filtros-municipios.md`.
|
||||
- **DEPLOY EM PRODUÇÃO REALIZADO (2026-07-23).** A cadeia destrutiva da remodelagem (`20260721_020109_remodel_municipalities` → `20260723_200000_remodel_municipalities` + `20260723_202000_reconcile_municipality_remodel`) foi aplicada em produção pelos builds Vercel de 2026-07-23 (deploys production READY dos commits `a7b8f1b`/`c7a1b74`/`59868a9`). **Este item supersede toda menção "deploy pendente" nas entradas abaixo.** Pendências operacionais: smoke pós-deploy + onboarding do time (Onda 0 §2/§4 em [`docs/roadmap.md`](../../../docs/roadmap.md)); hold de PII real segue no lote jurídico.
|
||||
- **Hardening de engenharia entregue e em produção (2026-07-23, Fases 0–6):** (0) access lockdown — `users`/`signature`/`subscription`/`consent` admin-only, escrita de CMS (`post`/`tag`/`media`/`petition`) admin-only, gates de rota do leader em `demandas*`/`planos*`, `createLeaderSupporter` com escopo correto, `candidate` tratado como staff irrestrito em todas as superfícies; (1) tooling gate — knip no CI (`.github/workflows/ci.yml`, mirror GitHub), `pnpm lint --max-warnings=0`, ban `as never` (helpers `hookFilledCreateData`/`stub<T>`), tsconfig consolidado + `noUnusedLocals`, ~12 módulos mortos deletados; (2) caching — artefato TSE commitado (`pnpm build:election-aggregates` → `src/lib/electionAggregates/`, loader `bahiaElectionAggregates.ts`), `unstable_cache` com tag `election-tse` nos loaders de eleições, `loadMunicipalityScope` (React `cache()`) dedupe dashboard+mapa+lista; (3) pending honesto — bug de revalidação do toggle de tarefa, `CampaignListPendingBoundary` esmaecendo resultados, transição no compare do mapa, mapa do dashboard + abas do detalhe em Suspense; (4) state scoping — hover do mapa isolado em `MunicipalityMapSelection`, provider de cenário estreitado, `LeaderContactForm` extraído como ilha cliente; (5) estrutura — `campaignAccess` dividido em `src/utilities/access/*` (re-export preservado), `supporterImport.ts` separado, `runStaffEntityMutation` + `runCampaignRedirectFormAction` dedupando twins e 4 ladders de formActions, rename `PLAZA_*`→`MUNICIPALITY_*` concluído; (6) docs + regra `.cursor/rules/engineering-standards.mdc`. Tracker: [`docs/IMPROVE-CODE-QUALITY-PLAN.md`](../../../docs/IMPROVE-CODE-QUALITY-PLAN.md) · ledger: [`docs/TECH-DEBT.md`](../../../docs/TECH-DEBT.md) · mapa de testes: [`docs/TESTING.md`](../../../docs/TESTING.md).
|
||||
- **Hardening de engenharia entregue e em produção (2026-07-23, Fases 0–6):** (0) access lockdown — `users`/`signature`/`subscription`/`consent` admin-only, escrita de CMS (`post`/`tag`/`media`/`petition`) admin-only, gates de rota do leader em `demandas*`/`planos*`, `createLeaderSupporter` com escopo correto, `candidate` tratado como staff irrestrito em todas as superfícies; (1) tooling gate — knip no CI (`.github/workflows/ci.yml`, mirror GitHub), `pnpm lint --max-warnings=0`, ban `as never` (helpers `hookFilledCreateData`/`stub<T>`), tsconfig consolidado + `noUnusedLocals`, ~12 módulos mortos deletados; (2) caching — artefato TSE commitado (`pnpm build:election-aggregates` → `src/lib/electionAggregates/`, loader `bahiaElectionAggregates.ts`), `unstable_cache` com tag `election-tse` nos loaders de eleições, `loadMunicipalityScope` (React `cache()`) dedupe dashboard+mapa+lista; (3) pending honesto — bug de revalidação do toggle de tarefa, `CampaignListPendingBoundary` esmaecendo resultados, transição no compare do mapa, mapa do dashboard + abas do detalhe em Suspense; (4) state scoping — hover do mapa isolado em `MunicipalityMapSelection`, provider de cenário estreitado, `LeaderContactForm` extraído como ilha cliente; (5) estrutura — `campaignAccess` dividido em `src/utilities/access/*` (re-export preservado), `supporterImport.ts` separado, `runStaffEntityMutation` + `runCampaignRedirectFormAction` dedupando twins e 4 ladders de formActions, rename `PLAZA_*`→`MUNICIPALITY_*` concluído; (6) docs + regra `.agents/rules/engineering-standards.mdc`. Tracker: [`docs/IMPROVE-CODE-QUALITY-PLAN.md`](../../../docs/IMPROVE-CODE-QUALITY-PLAN.md) · ledger: [`docs/TECH-DEBT.md`](../../../docs/TECH-DEBT.md) · mapa de testes: [`docs/TESTING.md`](../../../docs/TESTING.md).
|
||||
- **Remodelagem Municípios entregue em código (2026-07-23; deploy pendente — migrações `20260723_200000_remodel_municipalities` + `20260723_202000_reconcile_municipality_remodel` são destrutivas para a vertical campanha).** Decisões pós-reunião 2026-07-23: rename Praça→Município (`municipality`, `/campanha/municipios`); **435** entradas (Camaçari única; Salvador 19 zonas); role `candidate` (visão irrestrita); demandas staff-only; leader lockdown (ferramenta de contatos de apoiadores); dobradinhas (`stateDeputy`); mapa no Início (dashboard). Plano-mestre: [`remodelagem-municipios.md`](../../../docs/plans/remodelagem-municipios.md) (substitui `remodelagem-pracas.md`).
|
||||
- **A10 entregue em código (2026-07-23; deploy pendente com remodelagem):** cenários pessimista/média/otimista em `votePledge.estimatedVotes` e `municipality.expectedVotes` (groups + migration `20260723_124200_add_vote_estimate_scenarios`, backfill scalar→`central`); agregação por cenário em `votePledgeData`/`municipalityMapData`/overview/dashboard; seletor de cenário no mapa 2026; lista/dashboard com média + faixa; liderança intacta (`declaredVotes` único). Plano: [`cenarios-estimativa-votos.md`](../../../docs/plans/cenarios-estimativa-votos.md). Desbloqueia **E8**.
|
||||
- **Polish overview “Votos estimados” (2026-07-23):** `MunicipalityEstimateScenarioProvider` sincroniza Cenário do mapa com overview + células da lista; seletor Cenário visível em qualquer ano (hint quando ≠2026); labels `Média nas Praças filtradas` + `Pessimista · Otimista`; `sem estimativa` sob o hero. Critique: `.impeccable/critique/2026-07-23T21-29-20Z__src-components-campaign-municipalitylistoverview-tsx.md`.
|
||||
|
|
@ -208,13 +208,13 @@ alwaysApply: false
|
|||
- Em 2026-07-24, **uma única série por cenário — "Metas" eliminadas:** o grupo `municipality.voteGoals` ("Meta Bom/Regular/Mínimo") duplicava o conceito de votos estimados e foi removido do app (collection, zod, view models, form/card, `utilities/voteGoals.ts`); a série do município é `expectedVotes` (pessimista/média/otimista). Planilha EXPECTATIVA mapeia **Bom→otimista, Regular→média, Mínimo→pessimista**. Migration `20260724_133600_drop_municipality_vote_goals` com backfill metas→estimativas (estimativa existente vence). **Supersede** o "não fundir com `voteGoals`" da decisão A10 abaixo. **Rejeitado:** manter os dois grupos com semânticas distintas (meta de planejamento × estimativa) — a mesa trabalha com um número por cenário.
|
||||
- Em 2026-07-24, **E4R overwrite-always:** `pnpm db:seed:projecao` sempre sobrescreve `expectedVotes` + `priority` nas linhas casadas (planilha nova sobre DB já populado). **Rejeitado:** empty-only / `--overwrite` opt-in (quebraria o re-seed). Dry-run continua obrigatório antes de produção.
|
||||
- Em 2026-07-23, **access explícito em toda collection (hardening Fase 0):** o default do Payload ("qualquer autenticado pode CRUD") é tratado como bug; toda collection declara `access` explícito — `users`/`signature`/`subscription`/`consent` só Payload admin (`payloadAdminOnly`), escrita de CMS admin-only com leitura pública preservada. JWTs de `campaignUser` não operam mais essas collections via `/api`. **Rejeitado:** confiar no default do Payload; RBAC só na camada de UI.
|
||||
- Em 2026-07-23, **padrões de engenharia vigentes (hardening Fases 1–6):** zero lint warnings (`--max-warnings=0`); `as never` banido (helpers tipados `hookFilledCreateData` / `stub<T>` nos testes); knip no CI com files/dependencies em nível de erro; dead code se apaga imediatamente após qualquer mudança; convenção `lib/` (dado estático + lógica pura) vs `utilities/` (runtime Payload/Next); caching ladder (React `cache()` → `unstable_cache`+tag → artefato commitado). Regra sempre aplicada: [`.cursor/rules/engineering-standards.mdc`](../engineering-standards.mdc); débitos: [`docs/TECH-DEBT.md`](../../../docs/TECH-DEBT.md).
|
||||
- Em 2026-07-23, **auto-save sem botão Salvar:** campos de edição devem persistir automaticamente sempre que for seguro (change de select, blur ou debounce curto); sem botão “Salvar” em edição in-context / campo único. Submit explícito só para formulários multi-campo atômicos, nota/confirmação ou consentimento. Princípio 4 de [`PRODUCT.md`](../../../PRODUCT.md); regra Cursor [`.cursor/rules/campanha-edit-where-you-see.mdc`](../campanha-edit-where-you-see.mdc). **Rejeitado / supersede:** preferência B9 por Enter + botão Salvar em quick-edit; Save “por precaução” em Popover.
|
||||
- Em 2026-07-23, **padrões de engenharia vigentes (hardening Fases 1–6):** zero lint warnings (`--max-warnings=0`); `as never` banido (helpers tipados `hookFilledCreateData` / `stub<T>` nos testes); knip no CI com files/dependencies em nível de erro; dead code se apaga imediatamente após qualquer mudança; convenção `lib/` (dado estático + lógica pura) vs `utilities/` (runtime Payload/Next); caching ladder (React `cache()` → `unstable_cache`+tag → artefato commitado). Regra sempre aplicada: [`.agents/rules/engineering-standards.mdc`](../engineering-standards.mdc); débitos: [`docs/TECH-DEBT.md`](../../../docs/TECH-DEBT.md).
|
||||
- Em 2026-07-23, **auto-save sem botão Salvar:** campos de edição devem persistir automaticamente sempre que for seguro (change de select, blur ou debounce curto); sem botão “Salvar” em edição in-context / campo único. Submit explícito só para formulários multi-campo atômicos, nota/confirmação ou consentimento. Princípio 4 de [`PRODUCT.md`](../../../PRODUCT.md); regra Cursor [`.agents/rules/campanha-edit-where-you-see.mdc`](../campanha-edit-where-you-see.mdc). **Rejeitado / supersede:** preferência B9 por Enter + botão Salvar em quick-edit; Save “por precaução” em Popover.
|
||||
- Em 2026-08-02, **WhatsApp no produto = só `wa.me` (supersede D3–D5 de 2026-07-23):** bridge não oficial / QR / sidecar / número pessoal pareado descartados — risco de ban do chip do assessor/CG. Deep link `wa.me` (humano envia no app dele) permanece para convites, share e kit. **Rejeitado também:** WABA; disparo em massa (TSE art. 33); chatbot eleitoral. Issues #30–#32 `wontfix`.
|
||||
- Em 2026-07-23, **estimativas staff em três cenários (A10):** pessimista / média (`central`) / otimista no pledge e no total da Praça; liderança declara um valor; default de leitura = média; não fundir com `voteGoals`. **Rejeitado:** um único estimado; expor faixa à liderança; três choropleths. Desbloqueia E8.
|
||||
- Em 2026-07-21, **embasamento de produto/domínio via `docs/research/`:** decisões de análise territorial e mapa citam o relatório de discovery (aprovado 2026-07-21) antes de inventar métrica nova. Regras derivadas: leitura relativa (quantis/LQ/rank/captura) sobre % absoluto; limiares defesa/ataque 35/20/10 degeneram para DF e serão recalibrados com âncoras relativas (E10); roll-off (brancos+nulos DF − majoritária) é o headroom de orientação; abstenção estrutural corrige denominador (válidos projetados) e não é mercado; agregação regional default = Território de Identidade com salvaguardas MAUP (praça manda no voto, TI na logística). **Rejeitado:** cartogramas; pesquisa estadual de intenção para DF; persuasão de território hostil como funcionalidade.
|
||||
- Em 2026-07-21, **toolchain TypeScript dual:** `typescript` → `@typescript/typescript6@6.0.2` (API/editor/ESLint + `tsc6`); `typescript-7` → `typescript@7.0.2` (Go `tsc` para `pnpm typecheck`). Motivo: typescript-eslint peer `<6.1.0` e API estável só em TS ~7.1. Não usar `@typescript/native-preview`/`tsgo` (canal nightly). `typecheck:tsc6` existe para paridade. Ambient CSS/SCSS em `src/css-modules.d.ts` (TS6 `noUncheckedSideEffectImports`).
|
||||
- Em 2026-07-21, **decisão de produto (Field Desk):** em `/campanha`, superfícies staff de visualização que mostram dados mutáveis devem oferecer edição no contexto quando o access permitir (“edit where you see”) — princípio 3 de [`PRODUCT.md`](../../../PRODUCT.md); regra Cursor [`.cursor/rules/campanha-edit-where-you-see.mdc`](../campanha-edit-where-you-see.mdc). Precedente: **B9** ([`edicao-rapida-lista-pracas.md`](../../../docs/plans/edicao-rapida-lista-pracas.md) — `MunicipalityList*Control` + `municipalityStaffFormActions`). Complementado em 2026-07-23 pelo princípio **Auto-save, no Save button**. **Rejeitado:** lista/detalhe só-leitura com toda mutação em `/editar`; data-grid / planilha full-row; service genérico de “quick edit”. `/editar` e Sheets longos ficam para formulários multi-campo, campos raros e fluxos com nota/confirmação. Liderança continua no escopo já definido (sem campos staff-only).
|
||||
- Em 2026-07-21, **decisão de produto (Field Desk):** em `/campanha`, superfícies staff de visualização que mostram dados mutáveis devem oferecer edição no contexto quando o access permitir (“edit where you see”) — princípio 3 de [`PRODUCT.md`](../../../PRODUCT.md); regra Cursor [`.agents/rules/campanha-edit-where-you-see.mdc`](../campanha-edit-where-you-see.mdc). Precedente: **B9** ([`edicao-rapida-lista-pracas.md`](../../../docs/plans/edicao-rapida-lista-pracas.md) — `MunicipalityList*Control` + `municipalityStaffFormActions`). Complementado em 2026-07-23 pelo princípio **Auto-save, no Save button**. **Rejeitado:** lista/detalhe só-leitura com toda mutação em `/editar`; data-grid / planilha full-row; service genérico de “quick edit”. `/editar` e Sheets longos ficam para formulários multi-campo, campos raros e fluxos com nota/confirmação. Liderança continua no escopo já definido (sem campos staff-only).
|
||||
- Núcleo Eleitoral é a unidade operacional; Zona TSE é uma referência oficial adicional.
|
||||
- Todo núcleo exige geografia; natureza organizativa e setor são dimensões complementares.
|
||||
- Exclusão no app é substituída por arquivamento.
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ pnpm i # se node_modules ausente/stale
|
|||
|
||||
### Cloud (sem Docker)
|
||||
|
||||
Não use `pnpm db:start`. Postgres via `.cursor/environment.json`. `gate:fast` / `gate:push` não precisam de DB. **Proibido** `git push --no-verify` no fechamento.
|
||||
Não use `pnpm db:start`. Postgres via `.agents/environment.json`. `gate:fast` / `gate:push` não precisam de DB. **Proibido** `git push --no-verify` no fechamento.
|
||||
|
||||
## Passo 1 — Sessão (Issue já claimada)
|
||||
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ Create a rules file that persists across sessions. This is the highest-leverage
|
|||
```
|
||||
|
||||
**Equivalent files for other tools:**
|
||||
- `.cursorrules` or `.cursor/rules/*.md` (Cursor)
|
||||
- `.cursorrules` or `.agents/rules/*.md` (Cursor)
|
||||
- `.windsurfrules` (Windsurf)
|
||||
- `.github/copilot-instructions.md` (GitHub Copilot)
|
||||
- `AGENTS.md` (OpenAI Codex)
|
||||
|
|
|
|||
|
|
@ -46,8 +46,8 @@ Method: the engineering skills this repo follows (improve-code-quality, clean-co
|
|||
|
||||
Read, in this order:
|
||||
|
||||
1. `.cursor/rules/engineering-standards.mdc` — gates, type honesty, client boundary, caching ladder, access control.
|
||||
2. `.cursor/rules/codebase-map.mdc` — dependency direction, where things live, the list system, invariants.
|
||||
1. `.agents/rules/engineering-standards.mdc` — gates, type honesty, client boundary, caching ladder, access control.
|
||||
2. `.agents/rules/codebase-map.mdc` — dependency direction, where things live, the list system, invariants.
|
||||
3. `docs/ARCHITECTURE.md` — layers, bounded contexts, decision log.
|
||||
4. `AGENTS.md` — operational rules + "Recently resolved" history (Pass 1, Pass 2, every post-Pass-2 delivery's /simplify findings).
|
||||
5. `docs/AGENT-OPS.md` — paradigma de agentes paralelos vigente (claim→PR→main, skills plan-issue / work-issue / agent-work-issue / project-status). O audit avalia o repo **contra** esse fluxo, não contra o fluxo legacy de roadmap.md.
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ Production is a live **Neon Postgres** with real citizens' PII. Local developmen
|
|||
|
||||
## Cursor Cloud (sem Docker)
|
||||
|
||||
VMs Cloud **não rodam** `docker compose` / `pnpm db:start`. Postgres nativo: `.cursor/environment.json` (`cloud-setup.sh` + `ensure-postgres.sh`). Mesmos URLs `localhost:5432/teqo` e `teqo_test`. Agentes em `work-issue` / `agent-work-issue`: não tente Docker; `gate:fast`/`gate:push` não precisam de banco.
|
||||
VMs Cloud **não rodam** `docker compose` / `pnpm db:start`. Postgres nativo: `.agents/environment.json` (`cloud-setup.sh` + `ensure-postgres.sh`). Mesmos URLs `localhost:5432/teqo` e `teqo_test`. Agentes em `work-issue` / `agent-work-issue`: não tente Docker; `gate:fast`/`gate:push` não precisam de banco.
|
||||
|
||||
## Local connection values
|
||||
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ Objetivo: working tree limpa **antes** do rebase, sem pedir autorização. Escol
|
|||
| # | Condição | Caminho |
|
||||
| --- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- |
|
||||
| 1 | Há secretos / credenciais / env local no dirty set (`.env`, `.env.*`, `credentials.json`, `*.pem`, tokens óbvios no diff) | **stash** |
|
||||
| 2 | Dirty é só ruído local / efêmero: untracked scratch, IDE/OS (`.DS_Store`, `.idea/`, `*.swp`), cache, arquivos fora de `src/` `tests/` `docs/` `scripts/` `.cursor/skills/` `.github/` e sem relação com o tip da branch | **stash** |
|
||||
| 2 | Dirty é só ruído local / efêmero: untracked scratch, IDE/OS (`.DS_Store`, `.idea/`, `*.swp`), cache, arquivos fora de `src/` `tests/` `docs/` `scripts/` `.agents/skills/` `.github/` e sem relação com o tip da branch | **stash** |
|
||||
| 3 | Dirty é mistura: parte parece WIP da feature **e** parte é ruído/local/secrets → **não** faça commit parcial no escuro | **stash** |
|
||||
| 4 | Diff é WIP intencional da feature: toca os mesmos paths (ou domínio) de `origin/main...HEAD`, ou continua o intent dos commits recentes da branch; dá para redigir **uma** mensagem de commit coerente com o estilo do repo | **commit** |
|
||||
| 5 | Branch ainda sem commits próprios (`origin/main..HEAD` vazio) mas o dirty é claramente o trabalho da feature (plano/roadmap item, arquivos de entrega) e a mensagem fecha em uma frase | **commit** |
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ Idênticos a `agent-work-issue`:
|
|||
- `capture-review-debts` **com** gate humano (Passo 5 daquela skill) — não use o modo autônomo do pool
|
||||
- `pnpm push` → PR Ready `--base main` + `Closes #N` → auto-merge → `gh pr checks --watch --required`
|
||||
|
||||
Detalhes, Prep Cloud, invariantes e templates: leia [`agent-work-issue/SKILL.md`](../agent-work-issue/SKILL.md) e os arquivos em `.cursor/skills/work-issue/` (`engineering-brief.md`, `implementation-template.md`, `decision-quality.md`).
|
||||
Detalhes, Prep Cloud, invariantes e templates: leia [`agent-work-issue/SKILL.md`](../agent-work-issue/SKILL.md) e os arquivos em `.agents/skills/work-issue/` (`engineering-brief.md`, `implementation-template.md`, `decision-quality.md`).
|
||||
|
||||
## Resumo final
|
||||
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ Leia o que for relevante **antes** de travar a abordagem no `*-impl.md`. Não in
|
|||
|
||||
## Pinos do repo (sempre)
|
||||
|
||||
- `.cursor/rules/codebase-map.mdc` — direção `lib/` → `utilities/` → `components/` → `app/`; dono da feature
|
||||
- `.cursor/rules/engineering-standards.mdc` — gates, type honesty, client boundary, caching ladder, access
|
||||
- `.cursor/rules/security-critical.mdc` — quando tocar access/Local API/overrideAccess
|
||||
- `.agents/rules/codebase-map.mdc` — direção `lib/` → `utilities/` → `components/` → `app/`; dono da feature
|
||||
- `.agents/rules/engineering-standards.mdc` — gates, type honesty, client boundary, caching ladder, access
|
||||
- `.agents/rules/security-critical.mdc` — quando tocar access/Local API/overrideAccess
|
||||
- `AGENTS.md` — auth campanha, Consent fail-closed, transactions, naming, DB local
|
||||
- `docs/ARCHITECTURE.md` — se a mudança cruza verticais ou modelo de domínio
|
||||
|
||||
|
|
|
|||
|
|
@ -33,5 +33,6 @@ output/
|
|||
# Static assets and vendored agent material
|
||||
public/
|
||||
.agents/
|
||||
.agent/
|
||||
.cursor/
|
||||
docs/sheets/
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ Then run:
|
|||
- `pnpm test:e2e` — Playwright (requires the test DB schema and a free port)
|
||||
- `pnpm test:all` — unit + integration + E2E
|
||||
|
||||
Quality gates (also enforced by CI on the GitHub mirror): `pnpm lint` (zero warnings — `--max-warnings=0`), `pnpm typecheck`, and `pnpm exec knip` (dead files/dependencies fail; delete what your change orphaned). Standards: `.cursor/rules/engineering-standards.mdc`.
|
||||
Quality gates (also enforced by CI on the GitHub mirror): `pnpm lint` (zero warnings — `--max-warnings=0`), `pnpm typecheck`, and `pnpm exec knip` (dead files/dependencies fail; delete what your change orphaned). Standards: `.agents/rules/engineering-standards.mdc`.
|
||||
|
||||
## Tech Stack
|
||||
|
||||
|
|
@ -122,7 +122,7 @@ Quality gates (also enforced by CI on the GitHub mirror): `pnpm lint` (zero warn
|
|||
|
||||
## Campaign (`/campanha`)
|
||||
|
||||
Internal campaign tool for electoral nuclei, local leaderships, vote estimates, field updates, and WhatsApp invites. Authenticated separately from `/admin` via the `campaignUser` collection (`geral` / `coordenador` / `lideranca`). Operational status and decisions: [`.cursor/rules/projects/nucleos-eleitorais.mdc`](.cursor/rules/projects/nucleos-eleitorais.mdc). Conventions and deploy checklist: `AGENTS.md` (“Campaign auth” / “Campaign nuclei MVP”).
|
||||
Internal campaign tool for electoral nuclei, local leaderships, vote estimates, field updates, and WhatsApp invites. Authenticated separately from `/admin` via the `campaignUser` collection (`geral` / `coordenador` / `lideranca`). Operational status and decisions: [`.agents/rules/projects/nucleos-eleitorais.mdc`](.agents/rules/projects/nucleos-eleitorais.mdc). Conventions and deploy checklist: `AGENTS.md` (“Campaign auth” / “Campaign nuclei MVP”).
|
||||
|
||||
**Production blocker:** do not load real leadership data or enable invites until counsel-approved `Consent.key = 'lideranca-autopreenchimento'` exists. Absolute invite URLs require `NEXT_PUBLIC_SITE_URL` as an exact HTTPS DNS origin in production.
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ main → ci.yml full suite → vercel deploy --prod (se verde) → requeue se HE
|
|||
|
||||
**Skills:** `plan-issue` (intenção + Issues) → `work-issue` (humano: claim → impl plan → confirmação → execução) ou `agent-work-issue` (pool: já claimada → impl plan → execução sem pausa) → `/simplify` → `capture-review-debts` → PR `--base main` → `project-status`. `docs/roadmap.md` = legado congelado; fonte canônica = GitHub Issues.
|
||||
|
||||
- **Agente faz sozinho:** `pnpm agent:claim` → implementa → **`pnpm push`** → PR **Ready** (nunca draft) com `Closes #N` → `gh pr merge --auto --merge` → `gh pr checks --watch --required`. Regra always-on: `.cursor/rules/agent-pr-workflow.mdc`. Em Cursor Cloud: `ManagePullRequest` com `draft: false`, depois armar auto-merge via `gh pr merge --auto --merge` (o default draft da tool **não** vale neste repo).
|
||||
- **Agente faz sozinho:** `pnpm agent:claim` → implementa → **`pnpm push`** → PR **Ready** (nunca draft) com `Closes #N` → `gh pr merge --auto --merge` → `gh pr checks --watch --required`. Regra always-on: `.agents/rules/agent-pr-workflow.mdc`. Em Cursor Cloud: `ManagePullRequest` com `draft: false`, depois armar auto-merge via `gh pr merge --auto --merge` (o default draft da tool **não** vale neste repo).
|
||||
- **Só humano:** secrets Vercel (`VERCEL_TOKEN`, `VERCEL_ORG_ID`, `VERCEL_PROJECT_ID`), `POOL_GITHUB_TOKEN`, `pnpm configure:branch-protection`, editar envs Neon/Vercel.
|
||||
|
||||
### Dono do PR, dono do CI
|
||||
|
|
@ -91,7 +91,7 @@ Vercel Git builds: `scripts/vercel-ignore-build.sh` skipeia **todas** as branche
|
|||
|
||||
## Cursor Cloud
|
||||
|
||||
`.cursor/environment.json` instala deps + Postgres nativo + `db:seed:minimal`. Sem secrets de prod. Preferir `pnpm push`; escape `git push --no-verify` só no cutover documentado acima.
|
||||
`.agents/environment.json` instala deps + Postgres nativo + `db:seed:minimal`. Sem secrets de prod. Preferir `pnpm push`; escape `git push --no-verify` só no cutover documentado acima.
|
||||
|
||||
## Agent pool
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ flowchart LR
|
|||
|
||||
- **`src/lib/`** — lógica pura e dados estáticos, importável de client e server: catálogos (`municipalityCatalog`, `bahiaTerritories`, geometrias TopoJSON), schemas zod (`lib/schemas/*`), helpers puros (`phone`, `slug`, `wordStartFilter`, `voteEstimate`, `electionFormat`, `voteTrend`), constantes client-safe (`campaignConsentKeys`, `campaignRoles`), artefato TSE (`electionAggregates/` + `bahiaElectionAggregates.ts`). `lib/` **nunca importa de `utilities/`** (as 9 inversões históricas foram zeradas no Pass 2 W2).
|
||||
- **`src/utilities/`** — código acoplado a Payload/Next. Loaders que tocam banco ou `unstable_cache` são marcados **`import 'server-only'`** na primeira linha (21 marcados no Pass 2). Módulos de UI-helper client-safe (ex.: `municipalityListUrl`, `supporterUi`) ficam aqui sem a marca por importarem apenas TIPOS do Payload. **Subpastas de domínio (P3-J):** `access/` (RBAC), `municipality/`, `supporter/`, `territory/`, `leadership/`, `visit/`, `webauthn/` — imports diretos sem barrels. O top-level é pinado por convenção programática: um módulo novo top-level quebra o build até ser registrado (o gatilho D1 do Pass 2 codificado — 3 módulos novos de um domínio no mês ⇒ subpasta).
|
||||
- **`src/collections/` + `src/globals/`** — o modelo de domínio É o Payload. Toda collection declara `access` explicitamente; hooks passam `req` (transação) — ver `AGENTS.md` e `.cursor/rules/security-critical.mdc`.
|
||||
- **`src/collections/` + `src/globals/`** — o modelo de domínio É o Payload. Toda collection declara `access` explicitamente; hooks passam `req` (transação) — ver `AGENTS.md` e `.agents/rules/security-critical.mdc`.
|
||||
- **`src/components/campaign/`** — subpastas por domínio (Pass 2 W2): `municipality/ activity/ supporter/ leadership/ advisor/ demand/ organization/ stateDeputy/ votePledge/ invite/ map/ dashboard/ auth/ shell/ shared/`. `shared/` é o sistema transversal (listas, tabela, comboboxes); `shell/` é o chrome do app (sidebar, nav, PWA).
|
||||
- **Atravessando a fronteira client:** um client component nunca importa um módulo de dados de servidor por VALOR. Tipos/constantes compartilhados vivem num módulo de contrato client-safe — precedentes: `municipalityMapContract.ts` (mapa), `votePledgeViews.ts` (matemática de pledges; loaders em `votePledgeData.ts` são `server-only`), `lib/campaignRoles.ts` (predicados de role para a sidebar — a fonte da qual `utilities/access/shared.ts` deriva). `import type` é sempre seguro.
|
||||
|
||||
|
|
@ -105,4 +105,4 @@ Dois contexts principais + um de suporte, espelhados nos prefixos de módulo e n
|
|||
|
||||
## Manutenção deste documento
|
||||
|
||||
Atualize na mesma entrega que mover camadas, criar um context novo ou tomar uma decisão estrutural — junto com o mapa compacto do agente em `.cursor/rules/codebase-map.mdc` (convenção: os dois andam no MESMO PR).
|
||||
Atualize na mesma entrega que mover camadas, criar um context novo ou tomar uma decisão estrutural — junto com o mapa compacto do agente em `.agents/rules/codebase-map.mdc` (convenção: os dois andam no MESMO PR).
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -8,7 +8,7 @@ Ledger dos guardrails determinísticos colhidos de `kind:agent-miss` (fluxo `pnp
|
|||
|
||||
| Guarda | Origem | Classe | Mecanismo | Status |
|
||||
| ---------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- |
|
||||
| `agent:ship` exige stamp de /simplify casado com HEAD; PR Ready + auto-merge + watch até MERGED | [#83](https://github.com/fsolla/teqo/issues/83) | 3 (script + hooks) | `scripts/agent-ship.mjs`, `.cursor/hooks/guard-pr-create.mjs` (bloqueia `gh pr create` manual), `.cursor/hooks/pr-merge-watchdog.mjs` (re-engata com PR aberto) | vivo desde 2026-07-31 (PR #89); miss fechada no Pass 4 |
|
||||
| `agent:ship` exige stamp de /simplify casado com HEAD; PR Ready + auto-merge + watch até MERGED | [#83](https://github.com/fsolla/teqo/issues/83) | 3 (script + hooks) | `scripts/agent-ship.mjs`, `.agents/hooks/guard-pr-create.mjs` (bloqueia `gh pr create` manual), `.agents/hooks/pr-merge-watchdog.mjs` (re-engata com PR aberto) | vivo desde 2026-07-31 (PR #89); miss fechada no Pass 4 |
|
||||
| Alocador de municípios em specs — sem slug fixo + mutação; sem `municipio=<slug>` em e2e; regex de nome de catálogo ancorada | [#73](https://github.com/fsolla/teqo/issues/73) | 3 | `tests/unit/testMunicipalityAllocatorConventions.unit.spec.ts` (3 regras; mutações = assign/touch/create\*/`payload.update` municipality) | PR [#93](https://github.com/fsolla/teqo/pull/93) (Pass 4) |
|
||||
| Sheet compartilhada por lista — chip cells exigem `CampaignListSheetProvider`; invariante dev no overlay | [#52](https://github.com/fsolla/teqo/issues/52) | 3 + 5 | `tests/unit/sharedSheetHostConventions.unit.spec.ts`; `console.error` development-only em `CampaignCellEditOverlay` | PR [#94](https://github.com/fsolla/teqo/pull/94) (Pass 4) |
|
||||
| Navegação e2e assentada — goto→goto sem settle falha o build | [#54](https://github.com/fsolla/teqo/issues/54) | 3 | `tests/unit/e2eNavigationConventions.unit.spec.ts` (settle = await expect/waitForURL/click/reload/login/catch) | PR [#95](https://github.com/fsolla/teqo/pull/95) (Pass 4) |
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ Statuses: pending · in-progress · awaiting-evidence · done · deferred: \<rea
|
|||
| W0 | Safety net: pin list URL parsers + list loaders (unit + int smokes); TESTING/TECH-DEBT truth-up | [pinagem-superficies-lista.md](plans/pinagem-superficies-lista.md) | done | 2026-07-25 |
|
||||
| W1 | Generalized campaign list system (D1 core + municipality; D2 migrate entity triplet/demandas/apoiadores/assessores + delete superseded) | [sistema-listas-campanha.md](plans/sistema-listas-campanha.md) | done | 2026-07-25 |
|
||||
| W2 | Architecture decision (DDD/clean-arch/SDP evaluation → conventions + boundary fixes) + staged `components/campaign` subfolders | [decisao-arquitetura-dominios.md](plans/decisao-arquitetura-dominios.md) | done | 2026-07-25 |
|
||||
| W3 | `docs/ARCHITECTURE.md` + `.cursor/rules/codebase-map.mdc` | [mapa-mental-arquitetura.md](plans/mapa-mental-arquitetura.md) | done | 2026-07-25 |
|
||||
| W3 | `docs/ARCHITECTURE.md` + `.agents/rules/codebase-map.mdc` | [mapa-mental-arquitetura.md](plans/mapa-mental-arquitetura.md) | done | 2026-07-25 |
|
||||
| W4a | `electionInsights.ts` gut/split: extract `electionFormat`, keep voteTrend, delete dead clusters (before E10) | [split-election-insights.md](plans/split-election-insights.md) | done | 2026-07-25 |
|
||||
| W4b | knip unused-exports warn→error: delete zero-ref exports, un-export in-file symbols, config, CI flip | (tracker only) | done | 2026-07-25 |
|
||||
| W4c | Detail-page RSC extraction (`municipios/[slug]`, `planos/[slug]`) + dedupe detail-tab helper twins | (tracker only) | done | 2026-07-25 |
|
||||
|
|
@ -116,7 +116,7 @@ Statuses: pending · in-progress · awaiting-evidence · done · deferred: \<rea
|
|||
## Context
|
||||
|
||||
- **Started:** 2026-07-28 (audit executed and plan signed off same day).
|
||||
- **Trigger:** user-requested sweep for code smells + consolidation of similar components/hooks/functions (even when not identical — small behavior deltas accepted under the behavior-delta protocol), inspired by the engineering-standards skills catalog. The audit method is now codified as the reusable skill `.cursor/skills/engineering-audit/SKILL.md`.
|
||||
- **Trigger:** user-requested sweep for code smells + consolidation of similar components/hooks/functions (even when not identical — small behavior deltas accepted under the behavior-delta protocol), inspired by the engineering-standards skills catalog. The audit method is now codified as the reusable skill `.agents/skills/engineering-audit/SKILL.md`.
|
||||
- **Method:** read-only audit. Canon loaded (rules, ARCHITECTURE, TECH-DEBT, TESTING, `escala-dry-pos-*` plans, consolidation precedents, rejected-with-reason list); hotspot map (churn × size × static gates); **five parallel sweeps** (lib+scripts, utilities+access, components, app+collections+globals, tests); consolidation hunt under the anti-DRY rule (knowledge, not text); 11 open ledger rows re-verified.
|
||||
- **Baseline:** green — `tsc` 0 errors, `lint` 0 warnings, `knip` 0 findings (known `payload.config.ts` load error, P3), madge 0 cycles (650 files).
|
||||
- **Audit headlines (all measured):**
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
Movido do `AGENTS.md` em 2026-07-30. Referência sob demanda (config, collections, fields, hooks, queries, components, endpoints, drafts, plugins, best practices, gotchas). Não é contexto always-on.
|
||||
|
||||
Os padrões CRÍTICOS de segurança também vivem em `.cursor/rules/security-critical.mdc` (always-on).
|
||||
Os padrões CRÍTICOS de segurança também vivem em `.agents/rules/security-critical.mdc` (always-on).
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -1008,7 +1008,7 @@ export const myPlugin =
|
|||
|
||||
## Additional Context Files
|
||||
|
||||
For deeper exploration of specific topics, refer to the context files located in `.cursor/rules/`:
|
||||
For deeper exploration of specific topics, refer to the context files located in `.agents/rules/`:
|
||||
|
||||
### Available Context Files
|
||||
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ Ledger of known engineering debt. Items large enough to be scheduled work become
|
|||
| Multi-feature action bag: CRUD + CSV import pipeline + LGPD in one file (722 lines) | `src/app/(campaign)/campanha/actions/supporter.ts` | split CRUD vs import | done 2026-07-23 (`supporterImport.ts`) |
|
||||
| Clone twins: create/update/staff-assert/unique-conflict skeleton | `actions/organization.ts` ↔ `actions/stateDeputy.ts` | extract shared factory | done 2026-07-23 (`runStaffEntityMutation` in `campaignEntityActions.ts`) |
|
||||
| 14 near-identical `formActions.ts` try/catch→mapError→redirect/return ladders | `src/app/(campaign)/campanha/**/formActions.ts` | shared form-action wrapper | done 2026-07-25 (Pass 2 W4d): `runCampaignFormAction` + 13 ações migradas; exceções documentadas (atividades/formActions, apoiadores/[id], convite login). **C8 F4b ✓ 2026-07-27:** guard ampliado para `*FormActions.ts` + `taskActions.ts`; 6 irmãos migrados; `taskActions.ts` allowlisted — futuros siblings não driftam silenciosamente |
|
||||
| Flat 80+-file `src/utilities/` junk drawer; `lib/` vs `utilities/` boundary undocumented | `src/utilities/`, `src/lib/` | document convention + move misfiled modules | done 2026-07-23 (convention in `.cursor/rules/engineering-standards.mdc`; `RefreshRouteOnSave` moved to `components/`) |
|
||||
| Flat 80+-file `src/utilities/` junk drawer; `lib/` vs `utilities/` boundary undocumented | `src/utilities/`, `src/lib/` | document convention + move misfiled modules | done 2026-07-23 (convention in `.agents/rules/engineering-standards.mdc`; `RefreshRouteOnSave` moved to `components/`) |
|
||||
| Praça→Município rename leftovers in identifiers (`PLAZA_MAP_YEARS`, `ACCESSIBLE_PLAZA_IDS_CONTEXT_KEY`, …) | map/list utilities | finish rename | done 2026-07-23 |
|
||||
| Props→state `useEffect` mirrors | `MunicipalityListExpectedVotesControl`, comboboxes | key-remount or fully controlled | closed 2026-07-23 (accepted as correct — see Debt Ledger row) |
|
||||
| Detail-page RSCs mixing loading + tab UI + forms (300+ lines) | `municipios/[slug]/page.tsx`, `planos/[slug]/page.tsx` | extract tab loaders/sections | done 2026-07-25 (Pass 2 W4c): tabs em `MunicipalityDetailTabs.tsx` / `ActionPlanOverviewTab.tsx`; gêmeos de tab dedupados em `detailTabUi.ts` |
|
||||
|
|
|
|||
|
|
@ -214,7 +214,7 @@ Parâmetros (só relevantes ao backoff de retry de tick): `spawnRetryBackoff = p
|
|||
## 5. Seleção de modelo
|
||||
|
||||
- Fonte: frontmatter `model:` da Issue (escrito por `agent:register --model`, tabela de slugs
|
||||
em `.cursor/skills/model-selection/SKILL.md`).
|
||||
em `.agents/skills/model-selection/SKILL.md`).
|
||||
- Spawn: `model: { id: <slug>, params: [...] }` no body do `POST /v1/agents`. A API valida contra
|
||||
`GET /v1/models` (ids + aliases + params, ex.: `composer-2.5` com param `fast`).
|
||||
- **Namespace:** os slugs do repo (Task tool) e os da Cloud API são tabelas irmãs, não idênticas.
|
||||
|
|
@ -274,7 +274,7 @@ rotação documentada no runbook). `GITHUB_TOKEN` com `issues: write` (flip/come
|
|||
| `tests/unit/agentPoolModels.unit.spec.ts` | novo — mapping/fallback/validação | 2 |
|
||||
| `tests/unit/agentPoolPrompt.unit.spec.ts` | novo — contrato do prompt (issue N, sem claim, PR base stage) | 2 |
|
||||
| `docs/plans/agent-pool-orchestrator.md` | este plano + resultados do spike | 0 |
|
||||
| `.cursor/skills/agent-pool/SKILL.md` | novo — runbook humano (start/stop/status/triage) | 4 |
|
||||
| `.agents/skills/agent-pool/SKILL.md` | novo — runbook humano (start/stop/status/triage) | 4 |
|
||||
| `docs/AGENT-OPS.md` | linha na tabela de comandos + seção curta de secrets | 4 |
|
||||
| `docs/CHANGELOG-AGENTS.md` | uma entrada curta | 4 |
|
||||
|
||||
|
|
@ -347,7 +347,7 @@ ou deixar bloqueada.
|
|||
|
||||
- **Fase 0 — spike (30–45 min, antes de qualquer PR):** `GET /v1/me` + `GET /v1/models` (dump
|
||||
commitado neste plano); spawn de 1 agente de teste no repo com `model.id` explícito e prompt
|
||||
trivial; confirmar: boot via `.cursor/environment.json`, `gh` autenticado no worker, tempo real
|
||||
trivial; confirmar: boot via `.agents/environment.json`, `gh` autenticado no worker, tempo real
|
||||
de boot, formato exato do `agentId` cliente (`bc-…`) e o `409` no re-POST. Resultado: seção de
|
||||
evidências atualizada + tabela de mapeamento de modelos.
|
||||
- **Fase 1 — fundação read-only (appetite ~2–3h de sessão):** PR A — eligibility, state,
|
||||
|
|
@ -367,7 +367,7 @@ de spec — ops infra). **Schedule só ativa após o promote humano a `main`.**
|
|||
|
||||
- `pnpm agent:promote` (promote `stage→main` é humano — o pool nunca chama).
|
||||
- Qualquer `DATABASE_URL` de stage/prod no supervisor ou nos workers (Cloud usa
|
||||
`.cursor/cloud-setup.sh` + seed mínimo; o workflow não recebe secrets de banco).
|
||||
`.agents/cloud-setup.sh` + seed mínimo; o workflow não recebe secrets de banco).
|
||||
- Editar Issues `in-progress` de outros agentes/humanos (o pool só toca as que ele claimou).
|
||||
- Substituir ou alterar o fluxo `plan-issue` → `work-issue` para Issues normais.
|
||||
- Supervisor local (`/loop`, `while` em shell, daemon em VPS) como default — rejeitado.
|
||||
|
|
@ -488,7 +488,7 @@ EXPIRED`, com `git.branches[].prUrl`. SSE stream existe mas não é necessária
|
|||
cron "pode atrasar, nunca adianta". Avaliado como supervisor e rejeitado para v1 (D1); fica
|
||||
como plano B de superfície.
|
||||
Fonte: <https://cursor.com/docs/cloud-agent/automations>.
|
||||
7. **Ambiente do worker:** repo-file managed (`.cursor/environment.json` presente → install
|
||||
7. **Ambiente do worker:** repo-file managed (`.agents/environment.json` presente → install
|
||||
`pnpm install + cloud-setup.sh`: Postgres nativo + migrate + seed mínimo, sem secrets de
|
||||
stage/prod). Confirmado pelo MCP `cursor-cloud-environment-info` deste próprio run.
|
||||
8. **MCP `cursor-cloud`** (diagnóstico): `list-cloud-agents` com filtros de status/fonte,
|
||||
|
|
@ -500,7 +500,7 @@ EXPIRED`, com `git.branches[].prUrl`. SSE stream existe mas não é necessária
|
|||
Verificado neste run (Cloud Agent `bc-9cd1a18c-…`, repo fsolla/teqo):
|
||||
|
||||
- **Environment repo-file confirmado em produção:** o `environment-info` deste run reporta
|
||||
`source: Repository` + `environmentJsonPath: .cursor/environment.json` — workers spawnados
|
||||
`source: Repository` + `environmentJsonPath: .agents/environment.json` — workers spawnados
|
||||
pela API neste repo bootam com `pnpm install` + `cloud-setup.sh` (Postgres nativo + migrate +
|
||||
seed mínimo), sem secrets de stage/prod. Item 7 acima confirmado empiricamente.
|
||||
- **Formato de id:** runs usam `bc-<uuid>` (este run: `bc-9cd1a18c-3f2b-4661-b18b-401db63c1182`),
|
||||
|
|
|
|||
|
|
@ -165,4 +165,4 @@ Componentes:
|
|||
|
||||
- [fluxos-acao-primeiro-inicio.md](fluxos-acao-primeiro-inicio.md) · [cenarios-estimativa-votos.md](cenarios-estimativa-votos.md) · `src/lib/voteEstimate.ts` · `MunicipalityListExpectedVotesControl.tsx` · `VoteEstimateScenarioInputs.tsx` · collection `Municipality` hook de ordem
|
||||
- AGENTS.md — assimetria leader; `overrideAccess: false`
|
||||
- `PRODUCT.md` / `DESIGN.md` · `.cursor/rules/campanha-edit-where-you-see.mdc` (exceção submit explícito)
|
||||
- `PRODUCT.md` / `DESIGN.md` · `.agents/rules/campanha-edit-where-you-see.mdc` (exceção submit explícito)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ Implementado como planejado, com duas defasagens (o repo andou desde o rascunho
|
|||
|
||||
## Design (Impeccable)
|
||||
|
||||
Âncoras: `PRODUCT.md` (princípio 3 **Edit where you see**, princípio 4 **Auto-save, no Save button**, princípio 8 **Feel the action**) / `DESIGN.md` (register `product` — Field Desk) · tema `data-theme='campaign'` · regras `.cursor/rules/campanha-edit-where-you-see.mdc` e `.cursor/rules/campanha-action-feedback.mdc` · precedente vivo: [`MunicipalityListExpectedVotesControl.tsx`](../../src/components/campaign/municipality/MunicipalityListExpectedVotesControl.tsx) (máquina de auto-save com rollback) e o [`MunicipalityListTrendControl.tsx`](../../src/components/campaign/municipality/MunicipalityListTrendControl.tsx) atual (Popover + select — o que este item **não** deve repetir é o botão "Salvar" dele, hoje ainda sem o passe do B24).
|
||||
Âncoras: `PRODUCT.md` (princípio 3 **Edit where you see**, princípio 4 **Auto-save, no Save button**, princípio 8 **Feel the action**) / `DESIGN.md` (register `product` — Field Desk) · tema `data-theme='campaign'` · regras `.agents/rules/campanha-edit-where-you-see.mdc` e `.agents/rules/campanha-action-feedback.mdc` · precedente vivo: [`MunicipalityListExpectedVotesControl.tsx`](../../src/components/campaign/municipality/MunicipalityListExpectedVotesControl.tsx) (máquina de auto-save com rollback) e o [`MunicipalityListTrendControl.tsx`](../../src/components/campaign/municipality/MunicipalityListTrendControl.tsx) atual (Popover + select — o que este item **não** deve repetir é o botão "Salvar" dele, hoje ainda sem o passe do B24).
|
||||
|
||||
Na implementação (`implement-roadmap-item`): craft compacto → critique → polish (sem shape — é um único select sobre um campo que já existe, na mesma família visual dos outros popovers de lista).
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ Responsável: —
|
|||
|
||||
## Design (Impeccable)
|
||||
|
||||
Âncoras: `PRODUCT.md` (princípio 3 **Edit where you see**, princípio 4 **Auto-save, no Save button**, princípio 8 **Feel the action**) / `DESIGN.md` (register `product` — Field Desk) · tema `data-theme='campaign'` · regras `.cursor/rules/campanha-edit-where-you-see.mdc` e `.cursor/rules/campanha-action-feedback.mdc` · precedente vivo: [`MunicipalityListExpectedVotesControl.tsx`](../../src/components/campaign/municipality/MunicipalityListExpectedVotesControl.tsx).
|
||||
Âncoras: `PRODUCT.md` (princípio 3 **Edit where you see**, princípio 4 **Auto-save, no Save button**, princípio 8 **Feel the action**) / `DESIGN.md` (register `product` — Field Desk) · tema `data-theme='campaign'` · regras `.agents/rules/campanha-edit-where-you-see.mdc` e `.agents/rules/campanha-action-feedback.mdc` · precedente vivo: [`MunicipalityListExpectedVotesControl.tsx`](../../src/components/campaign/municipality/MunicipalityListExpectedVotesControl.tsx).
|
||||
|
||||
Na implementação (`implement-roadmap-item`): craft compacto → critique → polish (sem shape — o popover já existe e o padrão de auto-save já está no produto ao lado, na mesma linha da tabela).
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ As-built bate com as Decisões travadas de mutação/reuso; só o packaging de U
|
|||
|
||||
## Design (Impeccable)
|
||||
|
||||
Âncoras: `PRODUCT.md` (princípios 3 **Edit where you see**, 4 **Auto-save, no Save button**, 8 Feel the action; anti-goals "spreadsheet mode" e "always-mounted inputs on every row") / `DESIGN.md` (register `product`; Field Desk) · tema `data-theme='campaign'` · precedentes de interação [`AdvisorMunicipalityCell.tsx`](../../src/components/campaign/advisor/AdvisorMunicipalityCell.tsx) (B19 ✓ — chips removíveis + typeahead + otimista + `ResizeObserver`/"Ver mais…") e o desenho ainda não implementado do **B31** ([`dobradinhas-lista-liderancas.md`](dobradinhas-lista-liderancas.md) — chips + Popover + `Command`, sem "Ver mais…", para a mesma relação `leadership.stateDeputies` na direção oposta) · shells `CampaignTable` / `CampaignPageShell` · regras `.cursor/rules/campanha-edit-where-you-see.mdc` e `campanha-action-feedback.mdc`.
|
||||
Âncoras: `PRODUCT.md` (princípios 3 **Edit where you see**, 4 **Auto-save, no Save button**, 8 Feel the action; anti-goals "spreadsheet mode" e "always-mounted inputs on every row") / `DESIGN.md` (register `product`; Field Desk) · tema `data-theme='campaign'` · precedentes de interação [`AdvisorMunicipalityCell.tsx`](../../src/components/campaign/advisor/AdvisorMunicipalityCell.tsx) (B19 ✓ — chips removíveis + typeahead + otimista + `ResizeObserver`/"Ver mais…") e o desenho ainda não implementado do **B31** ([`dobradinhas-lista-liderancas.md`](dobradinhas-lista-liderancas.md) — chips + Popover + `Command`, sem "Ver mais…", para a mesma relação `leadership.stateDeputies` na direção oposta) · shells `CampaignTable` / `CampaignPageShell` · regras `.agents/rules/campanha-edit-where-you-see.mdc` e `campanha-action-feedback.mdc`.
|
||||
|
||||
Na implementação (`implement-roadmap-item`): craft compacto (a maior parte da interação já foi decidida no B31; craft aqui é sobretudo a direção nova + o clamp de overflow) → critique → polish. `harden`/`optimize` só sob gatilho do Passo 8.
|
||||
|
||||
|
|
@ -138,4 +138,4 @@ Depth check: reusa `CampaignTable`, `Popover`/`Command`/`Badge` do kit, `wordSta
|
|||
- `src/utilities/access/leaderships.ts` (`canReadLeadership`, `canManageLeadership`) — access que a leitura/escrita reusa sem alterar
|
||||
- `src/lib/wordStartFilter.ts` (`matchesAtWordStart`, `normalizeSearchPhrase`) — busca acento-insensível reusada
|
||||
- AGENTS.md — Campaign Municípios model, Transaction Safety, naming em inglês/copy em pt-BR
|
||||
- `.cursor/rules/campanha-edit-where-you-see.mdc`, `.cursor/rules/campanha-action-feedback.mdc` — princípios de UX herdados de Assessores/B31
|
||||
- `.agents/rules/campanha-edit-where-you-see.mdc`, `.agents/rules/campanha-action-feedback.mdc` — princípios de UX herdados de Assessores/B31
|
||||
|
|
|
|||
|
|
@ -172,4 +172,4 @@ Depth check: reusa `Popover`/`Command`/`Badge` do kit, `CampaignTable`, a lib pu
|
|||
- [`campaignRelationOptions.ts`](../../src/utilities/campaignRelationOptions.ts) (`loadMunicipalityOptions`) — escopo do assessor para sugestões
|
||||
- [`combobox-assessores-lista-municipios.md`](combobox-assessores-lista-municipios.md) (**B27**), [`dobradinhas-lista-liderancas.md`](dobradinhas-lista-liderancas.md) (**B31**), [`gerenciar-assessores.md`](gerenciar-assessores.md) (**B19 ✓**), [`ordenacao-filtros-lista-dobradinhas.md`](ordenacao-filtros-lista-dobradinhas.md) (**B33**)
|
||||
- AGENTS.md — Campaign Municípios model, Transaction Safety, naming inglês/copy pt-BR
|
||||
- `.cursor/rules/campanha-edit-where-you-see.mdc`, `.cursor/rules/campanha-action-feedback.mdc`
|
||||
- `.agents/rules/campanha-edit-where-you-see.mdc`, `.agents/rules/campanha-action-feedback.mdc`
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ Responsável: —
|
|||
|
||||
## Entregue (2026-07-27) — as-built
|
||||
|
||||
**O conflito foi resolvido a favor do pedido literal, emendando o anti-goal em vez de reabrir B28/B31/B32.** A coluna é **sempre editável em ponteiro fino** (`pointer-fine`): "×" no canto do chip só no hover/foco (posicionado em `absolute`, para revelar não mexer no tamanho do chip nem na linha) e input de busca no fim da linha de chips. Em **ponteiro grosso** (`pointer-coarse`) o toque em qualquer ponto da célula abre um **Drawer** com "×" de 44 px — um polegar rolando a tabela não pode ser convidado a distinguir "abrir o município" de "apagar o vínculo". O que decide não é largura de viewport, é a mídia `pointer:` (um tablet com mouse recebe o editor inline; um laptop touch recebe o Drawer). `PRODUCT.md` (princípio 3) e `.cursor/rules/campanha-edit-where-you-see.mdc` passaram a admitir input sempre montado **para relações por chips em `pointer-fine`**: o input É o readout, e um Popover por linha seria um clique a mais para um alvo que já está na tela. Nada aqui virou "modo de tabela" — o toggle de `AdvisorsTable` foi renomeado para **"Editar nome e contato"**, que é tudo o que ele ainda destrava depois desta entrega.
|
||||
**O conflito foi resolvido a favor do pedido literal, emendando o anti-goal em vez de reabrir B28/B31/B32.** A coluna é **sempre editável em ponteiro fino** (`pointer-fine`): "×" no canto do chip só no hover/foco (posicionado em `absolute`, para revelar não mexer no tamanho do chip nem na linha) e input de busca no fim da linha de chips. Em **ponteiro grosso** (`pointer-coarse`) o toque em qualquer ponto da célula abre um **Drawer** com "×" de 44 px — um polegar rolando a tabela não pode ser convidado a distinguir "abrir o município" de "apagar o vínculo". O que decide não é largura de viewport, é a mídia `pointer:` (um tablet com mouse recebe o editor inline; um laptop touch recebe o Drawer). `PRODUCT.md` (princípio 3) e `.agents/rules/campanha-edit-where-you-see.mdc` passaram a admitir input sempre montado **para relações por chips em `pointer-fine`**: o input É o readout, e um Popover por linha seria um clique a mais para um alvo que já está na tela. Nada aqui virou "modo de tabela" — o toggle de `AdvisorsTable` foi renomeado para **"Editar nome e contato"**, que é tudo o que ele ainda destrava depois desta entrega.
|
||||
|
||||
**Divergências do plano abaixo (que fica como registro do rascunho):**
|
||||
|
||||
|
|
@ -166,4 +166,4 @@ Depth check: reusa `Popover`/`Command`/`Badge` do kit, `CampaignTable`, `wordSta
|
|||
- [`MunicipalityEstimateScenarioContext.tsx`](../../src/components/campaign/municipality/MunicipalityEstimateScenarioContext.tsx) — precedente de provider cliente escopado
|
||||
- `tests/int/campaignLeadershipActions.int.spec.ts`, `tests/int/campaignAdvisorManagement.int.spec.ts`, `tests/unit/advisorMunicipalityPortfolio.unit.spec.ts`, `tests/helpers/campaignFixtures.ts`
|
||||
- AGENTS.md — Campaign Municípios model, Transaction Safety, naming inglês/copy pt-BR
|
||||
- `.cursor/rules/campanha-edit-where-you-see.mdc`, `.cursor/rules/campanha-action-feedback.mdc`
|
||||
- `.agents/rules/campanha-edit-where-you-see.mdc`, `.agents/rules/campanha-action-feedback.mdc`
|
||||
|
|
|
|||
|
|
@ -86,5 +86,5 @@ Componentes:
|
|||
|
||||
- `.github/workflows/ci-pr.yml` (job único atual), `ci.yml`, `ci-stage.yml` (comentário do subset)
|
||||
- `docs/AGENT-OPS.md` — tabela "CI por alvo" e "Contrato de PR"
|
||||
- AGENTS.md / `.cursor/rules/engineering-standards.mdc` — gate em duas velocidades, comandos bare
|
||||
- AGENTS.md / `.agents/rules/engineering-standards.mdc` — gate em duas velocidades, comandos bare
|
||||
- Run 30558184687 — baseline de wall-clock (9m37s serial até a falha)
|
||||
|
|
|
|||
|
|
@ -97,8 +97,8 @@ Componentes:
|
|||
- `.github/workflows/ci-pr.yml` (job `checks` / `migration-lock` como paralelo barato)
|
||||
- `.github/workflows/issue-done-on-main-merge.yml` — regex `closes|fixes`
|
||||
- `.github/pull_request_template.md` — `Closes #` default
|
||||
- `.cursor/skills/plan-issue/SKILL.md` — Passo 6
|
||||
- `.cursor/rules/agent-pr-workflow.mdc`
|
||||
- `.agents/skills/plan-issue/SKILL.md` — Passo 6
|
||||
- `.agents/rules/agent-pr-workflow.mdc`
|
||||
- `docs/GUARDRAILS.md`
|
||||
- `scripts/ci-scope.mjs` — precedente de classificar diff
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ Responsável: —
|
|||
|
||||
## Design (Impeccable)
|
||||
|
||||
Âncoras: `PRODUCT.md` (princípio 2 clareza sob pressão, 3 **Edit where you see**, 4 **Auto-save, no Save button**, 8 **Feel the action**) / `DESIGN.md` (register `product` — Field Desk) · tema `data-theme='campaign'` · regras `.cursor/rules/campanha-edit-where-you-see.mdc` e `.cursor/rules/campanha-action-feedback.mdc` · precedentes vivos: [`MunicipalityListExpectedVotesControl.tsx`](../../src/components/campaign/municipality/MunicipalityListExpectedVotesControl.tsx) (auto-save por endpoint JSON, mesma linha da tabela), [`AdvisorMunicipalityCell.tsx`](../../src/components/campaign/advisor/AdvisorMunicipalityCell.tsx) (chips removíveis + busca + gravação por delta), [`MunicipalityHeaderFilter.tsx`](../../src/components/campaign/municipality/MunicipalityHeaderFilter.tsx) (busca acento-insensível dentro de Popover, na **mesma coluna**).
|
||||
Âncoras: `PRODUCT.md` (princípio 2 clareza sob pressão, 3 **Edit where you see**, 4 **Auto-save, no Save button**, 8 **Feel the action**) / `DESIGN.md` (register `product` — Field Desk) · tema `data-theme='campaign'` · regras `.agents/rules/campanha-edit-where-you-see.mdc` e `.agents/rules/campanha-action-feedback.mdc` · precedentes vivos: [`MunicipalityListExpectedVotesControl.tsx`](../../src/components/campaign/municipality/MunicipalityListExpectedVotesControl.tsx) (auto-save por endpoint JSON, mesma linha da tabela), [`AdvisorMunicipalityCell.tsx`](../../src/components/campaign/advisor/AdvisorMunicipalityCell.tsx) (chips removíveis + busca + gravação por delta), [`MunicipalityHeaderFilter.tsx`](../../src/components/campaign/municipality/MunicipalityHeaderFilter.tsx) (busca acento-insensível dentro de Popover, na **mesma coluna**).
|
||||
|
||||
Na implementação (`implement-roadmap-item`): craft compacto → critique → polish (sem shape — o Popover, a célula e os dois padrões que este item combina já estão no produto).
|
||||
|
||||
|
|
|
|||
|
|
@ -112,4 +112,4 @@ Componentes:
|
|||
- `src/components/campaign/advisor/AdvisorsTable.tsx` (linhas ~86–93, ~411–437) — precedente de ícone de linha com disable por telefone
|
||||
- `tests/unit/campaignInviteInteractions.unit.spec.ts`, `tests/int/campaignInvite.int.spec.ts` — padrão de teste da action/UI de convite existente
|
||||
- AGENTS.md — Local API `overrideAccess: false` (já respeitado pela action reusada), Campaign auth
|
||||
- `PRODUCT.md` / `.cursor/rules/campanha-edit-where-you-see.mdc`, `.cursor/rules/campanha-action-feedback.mdc` — princípios de UI herdados
|
||||
- `PRODUCT.md` / `.agents/rules/campanha-edit-where-you-see.mdc`, `.agents/rules/campanha-action-feedback.mdc` — princípios de UI herdados
|
||||
|
|
|
|||
|
|
@ -37,5 +37,5 @@ Nenhum item bloqueado (moves per-domain em branches curtas); navegação de agen
|
|||
|
||||
## Referências
|
||||
|
||||
- `.cursor/rules/engineering-standards.mdc` (regra lib/utilities), AGENTS.md (estrutura), auditoria de fronteiras 2026-07-25
|
||||
- `.agents/rules/engineering-standards.mdc` (regra lib/utilities), AGENTS.md (estrutura), auditoria de fronteiras 2026-07-25
|
||||
- `src/utilities/campaignAccess.ts` (precedente de split within-layer com re-export surface)
|
||||
|
|
|
|||
|
|
@ -74,4 +74,4 @@ Nenhum neste item.
|
|||
- `.github/workflows/ci-pr.yml` — job `migration-lock`
|
||||
- `tests/int/homeSearchLeaderships.int.spec.ts` + `tests/int/homeSearchDemands.int.spec.ts` (padrão-alvo)
|
||||
- `scripts/lib/seed-minimal-manifest.mjs` — `MINIMAL_LEADERSHIPS`
|
||||
- `.cursor/skills/work-issue/SKILL.md` — Passo 6 (acompanhar checks até o merge)
|
||||
- `.agents/skills/work-issue/SKILL.md` — Passo 6 (acompanhar checks até o merge)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ Responsável: —
|
|||
|
||||
## Design (Impeccable)
|
||||
|
||||
Âncoras: `PRODUCT.md` (princípio 3 **Edit where you see**, 4 **Auto-save, no Save button**, 8 Feel the action; anti-goals "spreadsheet mode" e "always-mounted inputs on every row") / `DESIGN.md` (register `product`; Field Desk) · tema `data-theme='campaign'` · precedentes de interação [`AdvisorMunicipalityCell.tsx`](../../src/components/campaign/advisor/AdvisorMunicipalityCell.tsx) (B19 ✓ — chips removíveis + typeahead + otimista) e o popover de edição rápida da lista de municípios (B9 ✓ / **B27**) · shells `CampaignTable` / `CampaignPageShell` · regras `.cursor/rules/campanha-edit-where-you-see.mdc` e `campanha-action-feedback.mdc`.
|
||||
Âncoras: `PRODUCT.md` (princípio 3 **Edit where you see**, 4 **Auto-save, no Save button**, 8 Feel the action; anti-goals "spreadsheet mode" e "always-mounted inputs on every row") / `DESIGN.md` (register `product`; Field Desk) · tema `data-theme='campaign'` · precedentes de interação [`AdvisorMunicipalityCell.tsx`](../../src/components/campaign/advisor/AdvisorMunicipalityCell.tsx) (B19 ✓ — chips removíveis + typeahead + otimista) e o popover de edição rápida da lista de municípios (B9 ✓ / **B27**) · shells `CampaignTable` / `CampaignPageShell` · regras `.agents/rules/campanha-edit-where-you-see.mdc` e `campanha-action-feedback.mdc`.
|
||||
|
||||
Na implementação (`implement-roadmap-item`): craft compacto → critique → polish. `harden`/`optimize` só sob gatilho do Passo 8.
|
||||
|
||||
|
|
@ -135,7 +135,7 @@ Depth check: reusa `CampaignTable`, `Popover`/`Command`/`Badge` do kit, `wordSta
|
|||
- [`campaignRelationOptions.ts`](../../src/utilities/campaignRelationOptions.ts) — `loadStateDeputyOptions`
|
||||
- [`combobox-assessores-lista-municipios.md`](combobox-assessores-lista-municipios.md) (B27) · [`email-celular-lista-liderancas.md`](email-celular-lista-liderancas.md) (B28) · [`ordenacao-filtros-lista-liderancas.md`](ordenacao-filtros-lista-liderancas.md) (B29) · [`convite-whatsapp-lista-liderancas.md`](convite-whatsapp-lista-liderancas.md) (B30) · [`gerenciar-assessores.md`](gerenciar-assessores.md) (B19 ✓)
|
||||
- AGENTS.md — Campaign auth, naming, `overrideAccess: false`, escrita transacional, `Contact` join
|
||||
- `PRODUCT.md` / `DESIGN.md` — princípios 3, 4 e 8; Field Desk · `.cursor/rules/campanha-edit-where-you-see.mdc`
|
||||
- `PRODUCT.md` / `DESIGN.md` — princípios 3, 4 e 8; Field Desk · `.agents/rules/campanha-edit-where-you-see.mdc`
|
||||
|
||||
## Revisão na entrega (2026-07-26)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Pass 3 — Auditoria de engenharia e consolidação
|
||||
|
||||
**Data:** 2026-07-28 · **Método:** skill [`engineering-audit`](../../.cursor/skills/engineering-audit/SKILL.md) (Pass-style; cinco varreduras paralelas read-only) · **Tracker:** [IMPROVE-CODE-QUALITY-PLAN.md](../IMPROVE-CODE-QUALITY-PLAN.md) · **Ledger:** [TECH-DEBT.md](../TECH-DEBT.md)
|
||||
**Data:** 2026-07-28 · **Método:** skill [`engineering-audit`](../../.agents/skills/engineering-audit/SKILL.md) (Pass-style; cinco varreduras paralelas read-only) · **Tracker:** [IMPROVE-CODE-QUALITY-PLAN.md](../IMPROVE-CODE-QUALITY-PLAN.md) · **Ledger:** [TECH-DEBT.md](../TECH-DEBT.md)
|
||||
|
||||
## Contexto e manchetes
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ Este plano é o registro canônico desses follow-ups. Sem ele, o B3 pode embarca
|
|||
## Questões em aberto
|
||||
|
||||
- **API pública pós-lazy: manter `getMunicipalityFeature` sync após warm, ou só async loaders?** **Recomendação:** loaders async (`loadMunicipalityGeometryModule()` / `loadTerritoryGeometryModule()`) que resolvem o módulo já indexado; os getters sync atuais viram métodos do módulo carregado (ou ficam em submodule lazy). Evitar Promise em cada hover do mapa.
|
||||
- ~~**Onde vive o helper de cache CLI?**~~ **RESOLVIDO POR PRECEDENTE (`capture-review-debts` pós-B8+, 2026-07-27):** `scripts/lib/`. O B8+ precisou compartilhar a política de escala de chão entre os dois scripts de geometria e criou **`scripts/lib/topology.mjs`** — o primeiro módulo da pasta. A F2 **pousa nele** (`scripts/lib/cached-download.mjs`) em vez de abrir um segundo endereço: dois lares para código de CLI é exatamente a duplicação que esta fase existe para remover. A recomendação anterior (`src/lib/cliCachedDownload.ts`) fica **rejeitada** — `src/lib/` é client-safe por contrato (`.cursor/rules/codebase-map.mdc`) e um helper que faz `mkdir`/`fetch`/`writeFile` não pertence a uma pasta que o bundle do browser pode alcançar, mesmo que hoje ninguém o importe de lá.
|
||||
- ~~**Onde vive o helper de cache CLI?**~~ **RESOLVIDO POR PRECEDENTE (`capture-review-debts` pós-B8+, 2026-07-27):** `scripts/lib/`. O B8+ precisou compartilhar a política de escala de chão entre os dois scripts de geometria e criou **`scripts/lib/topology.mjs`** — o primeiro módulo da pasta. A F2 **pousa nele** (`scripts/lib/cached-download.mjs`) em vez de abrir um segundo endereço: dois lares para código de CLI é exatamente a duplicação que esta fase existe para remover. A recomendação anterior (`src/lib/cliCachedDownload.ts`) fica **rejeitada** — `src/lib/` é client-safe por contrato (`.agents/rules/codebase-map.mdc`) e um helper que faz `mkdir`/`fetch`/`writeFile` não pertence a uma pasta que o bundle do browser pode alcançar, mesmo que hoje ninguém o importe de lá.
|
||||
- **Unificar env `TSE_CACHE_DIR` / `GEOMETRIES_CACHE_DIR`?** **Recomendação:** não — um parâmetro `cacheDir` por chamada; cada script mantém sua env e pasta sob `data/`.
|
||||
|
||||
## Abordagem proposta
|
||||
|
|
|
|||
|
|
@ -160,4 +160,4 @@ Componentes:
|
|||
- `src/components/campaign/map/BahiaMap.tsx` (`:73-90` duas malhas) + `MunicipalityMapPanel.tsx` (ressalva; lista `zoneBreakdown` → fill-in [remover-lista-zonas-mapa-inicio.md](remover-lista-zonas-mapa-inicio.md)) — F3
|
||||
- `src/utilities/municipalityMapNavigation.ts` + `src/lib/municipalityProximity.ts` + `src/lib/bahiaGeometriesTypes.ts` + `tests/helpers/featureBounds.ts` — F4
|
||||
- AGENTS.md — geometrias B2/B8 F2, gate por entrega, `overrideAccess: false` com `user`
|
||||
- `.cursor/rules/engineering-standards.mdc` — "dead code dies immediately" (F4), depth check (F1/F2)
|
||||
- `.agents/rules/engineering-standards.mdc` — "dead code dies immediately" (F4), depth check (F1/F2)
|
||||
|
|
|
|||
|
|
@ -111,5 +111,5 @@ Depth check: nenhum módulo novo — três edições em dois arquivos que já do
|
|||
- `src/app/(campaign)/campanha/(app)/atividades/giros/page.tsx`
|
||||
- `src/app/(campaign)/campanha/(app)/municipios/page.tsx` — precedente de montagem boundary + results
|
||||
- `tests/unit/campaignListFilterNavigation.unit.spec.ts` — molde do teste
|
||||
- `.cursor/rules/engineering-standards.mdc` — § Loading feedback ("a região de RESULTADOS dima")
|
||||
- `.agents/rules/engineering-standards.mdc` — § Loading feedback ("a região de RESULTADOS dima")
|
||||
- `PRODUCT.md` / `DESIGN.md` — Field Desk
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ Dados: N/A — chore de DX.
|
|||
|
||||
## Contexto
|
||||
|
||||
`.husky/pre-push` é uma linha: `pnpm lint && pnpm format:check && pnpm typecheck`. Mas o fast gate exigido por `.cursor/rules/engineering-standards.mdc` (desde 2026-07-30) e por `work-issue` Passo 4.3 é **lint + tsc + test:unit + format:check + check:cycles**. Resultado: agentes e humanos pusham verde no hook e quebram no CI por unit/cycles que nunca rodaram localmente. Não existe pre-commit hook.
|
||||
`.husky/pre-push` é uma linha: `pnpm lint && pnpm format:check && pnpm typecheck`. Mas o fast gate exigido por `.agents/rules/engineering-standards.mdc` (desde 2026-07-30) e por `work-issue` Passo 4.3 é **lint + tsc + test:unit + format:check + check:cycles**. Resultado: agentes e humanos pusham verde no hook e quebram no CI por unit/cycles que nunca rodaram localmente. Não existe pre-commit hook.
|
||||
|
||||
Decisão de produto (2026-07-30, brief do lote CI): scripts DRY (`gate:fast`, `gate:push`), divisão pre-commit vs pre-push explícita, escape hatch documentado.
|
||||
|
||||
|
|
@ -43,9 +43,9 @@ Componentes:
|
|||
|
||||
- **`package.json`** — scripts `gate:fast`, `gate:ci` (`scripts/gate-ci.mjs`) e `gate:push` (= `gate:ci`).
|
||||
- **`.husky/pre-push`** — `pnpm gate:push`.
|
||||
- **`.cursor/rules/engineering-standards.mdc`** — item 3 do "After every change" passa a citar `pnpm gate:fast` / `pnpm gate:push`.
|
||||
- **`.agents/rules/engineering-standards.mdc`** — item 3 do "After every change" passa a citar `pnpm gate:fast` / `pnpm gate:push`.
|
||||
- **`docs/AGENT-OPS.md`** — linha do fast gate local atualizada para os scripts.
|
||||
- **`.cursor/skills/work-issue/SKILL.md`** — Passo 4.3/6.1 cita `pnpm gate:push`.
|
||||
- **`.agents/skills/work-issue/SKILL.md`** — Passo 4.3/6.1 cita `pnpm gate:push`.
|
||||
|
||||
Sem migration, sem código de app.
|
||||
|
||||
|
|
@ -69,5 +69,5 @@ Nenhum neste item.
|
|||
## Referências
|
||||
|
||||
- `.husky/pre-push` (linha atual), `package.json` (scripts de gate existentes)
|
||||
- `.cursor/rules/engineering-standards.mdc` — "Gate em duas velocidades"
|
||||
- `docs/AGENT-OPS.md` — fast gate local; `.cursor/skills/work-issue/SKILL.md` — Passo 4.3
|
||||
- `.agents/rules/engineering-standards.mdc` — "Gate em duas velocidades"
|
||||
- `docs/AGENT-OPS.md` — fast gate local; `.agents/skills/work-issue/SKILL.md` — Passo 4.3
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ Responsável: —
|
|||
|
||||
## Design (Impeccable)
|
||||
|
||||
Âncoras: `PRODUCT.md` § **Feel the action** · `.cursor/rules/campanha-action-feedback.mdc` · precedente `CampaignListPendingBoundary` / `CampaignListResults` / `useCampaignListTransition` (`src/components/campaign/shared/CampaignListPending.tsx`) e fill-in do compositor de giro ([feedback-pendente-compositor-giro.md](feedback-pendente-compositor-giro.md)) · tema `data-theme='campaign'`.
|
||||
Âncoras: `PRODUCT.md` § **Feel the action** · `.agents/rules/campanha-action-feedback.mdc` · precedente `CampaignListPendingBoundary` / `CampaignListResults` / `useCampaignListTransition` (`src/components/campaign/shared/CampaignListPending.tsx`) e fill-in do compositor de giro ([feedback-pendente-compositor-giro.md](feedback-pendente-compositor-giro.md)) · tema `data-theme='campaign'`.
|
||||
|
||||
Na implementação (`implement-roadmap-item`): craft compacto → critique → polish. Sem shape novo.
|
||||
|
||||
|
|
@ -104,7 +104,7 @@ Componentes:
|
|||
- `src/components/campaign/shared/CampaignListPending.tsx` — boundary, hook, results, `CampaignTransitionAnchor`
|
||||
- `docs/plans/chassis-wizard-campanha.md` (B59 ✓) · `docs/plans/header-mobile-wizard-campanha.md` (B75) · `docs/plans/busca-municipio-wizard.md` (B60 ✓)
|
||||
- `docs/plans/feedback-pendente-compositor-giro.md` — precedente não-lista
|
||||
- `.cursor/rules/campanha-action-feedback.mdc` · `PRODUCT.md` § Feel the action
|
||||
- `.agents/rules/campanha-action-feedback.mdc` · `PRODUCT.md` § Feel the action
|
||||
- AGENTS.md — sem Consent; naming
|
||||
|
||||
Qualidade de decisão: 4/5
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ Um humano ou agente novo se orienta no repo em minutos, sem arqueologia de git/A
|
|||
- Decision log: todas as decisões do Pass 2 (D1–D6) + as decisões estruturais herdadas (transações multi-collection, consent fail-closed, migrations only).
|
||||
- Cross-links para PRODUCT/DESIGN/CUSTOMER/research para o "porquê" — sem duplicar conteúdo.
|
||||
|
||||
**2. `.cursor/rules/codebase-map.mdc`** — mapa navegacional compacto (~150 linhas), always-applied, criado com o skill `create-rule`: onde vive cada coisa, como achar o dono de uma feature, convenção de manutenção ("atualizado no mesmo PR que move coisas").
|
||||
**2. `.agents/rules/codebase-map.mdc`** — mapa navegacional compacto (~150 linhas), always-applied, criado com o skill `create-rule`: onde vive cada coisa, como achar o dono de uma feature, convenção de manutenção ("atualizado no mesmo PR que move coisas").
|
||||
|
||||
## Regras
|
||||
|
||||
|
|
|
|||
|
|
@ -86,4 +86,4 @@ Componentes:
|
|||
|
||||
- `docs/roadmap.md` (linhas 57, 60, 61)
|
||||
- `AGENTS.md` — Campaign auth, Campaign nuclei MVP, transações, `Consent` por chave
|
||||
- `.cursor/rules/projects/nucleos-eleitorais.mdc`
|
||||
- `.agents/rules/projects/nucleos-eleitorais.mdc`
|
||||
|
|
|
|||
|
|
@ -164,4 +164,4 @@ Componentes (molde B33 — não re-extrair chrome):
|
|||
- `src/components/campaign/municipality/MunicipalitySortableHead.tsx`, `MunicipalityHeaderFilter.tsx`, `src/components/campaign/shared/CampaignTable.tsx` — origem da extração e destino das colunas
|
||||
- `src/collections/Leadership.ts`, `src/utilities/access/` — campos indexados (`supportStatus`, `sector`, `municipalities`, `user`) e escopo do assessor
|
||||
- AGENTS.md — Campaign auth e RBAC, `overrideAccess: false` com `user`, pessoa é sempre `Contact` + join, naming (identificadores em inglês, copy pt-BR), sem migration neste item
|
||||
- `PRODUCT.md` / `DESIGN.md` — Field Desk, anti-goals de dashboard, "Edit where you see" (não se aplica na v1 desta tela) · `.cursor/rules/campanha-action-feedback.mdc` (pending honesto no resultado)
|
||||
- `PRODUCT.md` / `DESIGN.md` — Field Desk, anti-goals de dashboard, "Edit where you see" (não se aplica na v1 desta tela) · `.agents/rules/campanha-action-feedback.mdc` (pending honesto no resultado)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ todos:
|
|||
content: 'Neon prod snapshot → branch stage; runbook refresh (nova branch + swap secret) via workflow_dispatch humano'
|
||||
status: pending
|
||||
- id: onda0-cursor-context
|
||||
content: 'AGENT-OPS.md + fatiar AGENTS + kernels + .cursorignore + Cloud env + hooks portáteis + standards fast-gate + PR template + README cheatsheet'
|
||||
content: 'AGENT-OPS.md + fatiar AGENTS + kernels + .agentignore + Cloud env + hooks portáteis + standards fast-gate + PR template + README cheatsheet'
|
||||
status: pending
|
||||
- id: onda0-remove-codeberg
|
||||
content: 'Remover Codeberg de package.json/AGENTS/TECH-DEBT/ci.yml e qualquer referência; GitHub = única casa'
|
||||
|
|
@ -221,13 +221,13 @@ Cloud env: `gh` autenticado (Cursor GitHub integration); sem secrets de stage/pr
|
|||
|
||||
## Cursor Cloud readiness
|
||||
|
||||
| Item | Ação |
|
||||
| -------- | --------------------------------------------------------------- |
|
||||
| Contexto | Fatiar AGENTS; kernels PRODUCT/DESIGN/CUSTOMER; `.cursorignore` |
|
||||
| Env | Compose Postgres + `migrate` + `db:seed:minimal` |
|
||||
| Hooks | Paths relativos |
|
||||
| Regra | PR base `stage`; nunca Neon; 1 Issue/run |
|
||||
| Brief | stdout do claim |
|
||||
| Item | Ação |
|
||||
| -------- | -------------------------------------------------------------- |
|
||||
| Contexto | Fatiar AGENTS; kernels PRODUCT/DESIGN/CUSTOMER; `.agentignore` |
|
||||
| Env | Compose Postgres + `migrate` + `db:seed:minimal` |
|
||||
| Hooks | Paths relativos |
|
||||
| Regra | PR base `stage`; nunca Neon; 1 Issue/run |
|
||||
| Brief | stdout do claim |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -248,7 +248,7 @@ Igual: `file-miss` → harvest → PR com `codebaseConventions`/ESLint → ledge
|
|||
4. **Stage DB** (Neon prod snapshot) + runbook refresh **semanal**.
|
||||
5. **Vercel preview** para branch `stage` na Onda 0.
|
||||
6. Labels/prio + scripts `claim|register|prioritize|file-miss|promote` + seed Issues (body = plan atual, `depends` do roadmap).
|
||||
7. Contexto Cursor: `AGENT-OPS.md`, fatiar AGENTS, kernels, `.cursorignore`, Cloud env (Compose+seed:minimal), hooks portáteis, standards fast-gate, PR template.
|
||||
7. Contexto Cursor: `AGENT-OPS.md`, fatiar AGENTS, kernels, `.agentignore`, Cloud env (Compose+seed:minimal), hooks portáteis, standards fast-gate, PR template.
|
||||
8. **README cheatsheet** — seção curta no topo do [`README.md`](README.md) para humanos: fluxo em 5 linhas, comandos `pnpm agent:*`, labels, o que o agente faz sozinho vs o que exige humano, links para `AGENT-OPS.md`/CI/skills. Não duplicar o setup local — só a operação agentic.
|
||||
|
||||
Ordenar: 0 primeiro (limpa base), depois 1/2, depois 3/4/5, depois 6/7/8.
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ flowchart LR
|
|||
- **`scripts/lib/agent-plan-lifecycle.mjs`:** puro — `resolveRegisterStateLabel({ hasPlan, explicitBlocked })`, `canPromotePlanIssue(issue)` (blocked + link `docs/plans/` + open + sem in-progress/done/in-prod).
|
||||
- **`scripts/agent-register.mjs`:** usa o helper; com `--plan` nasce `blocked` (mesmo sem `--blocked`); sem `--plan` preserva `ready` / `--blocked`.
|
||||
- **`scripts/agent-ready.mjs` + `pnpm agent:ready`:** flip `blocked`→`ready` idempotente; comenta motivo; recusa se não for “aguardando plano”.
|
||||
- **`.cursor/skills/plan-issue/SKILL.md`:** Passo 5 = gate duro (sem Issue/PR até OK explícito ao lote); Passo 6 = register → PR `Related #N` → merge → `agent:ready`.
|
||||
- **`.agents/skills/plan-issue/SKILL.md`:** Passo 5 = gate duro (sem Issue/PR até OK explícito ao lote); Passo 6 = register → PR `Related #N` → merge → `agent:ready`.
|
||||
- **`docs/AGENT-OPS.md` + skill `agent-pool` (menção curta) + nota em `capture-review-debts`:** contrato de labels / promote após plano em `main`.
|
||||
- **Tests:** `tests/unit/agentPlanLifecycle.unit.spec.ts` (register label + canPromote).
|
||||
- **Migration / Access / Consent / UI:** N/A (Impeccable A).
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ Omitido — superfície A (processo).
|
|||
|
||||
## Direção no codebase (hipótese)
|
||||
|
||||
- **Áreas prováveis:** `.cursor/skills/plan-issue/` (SKILL + checklist Passo 5/6), `scripts/agent-register.mjs`, elegibilidade do pool (`scripts/lib/agent-pool-eligibility.mjs` + pins em `tests/unit/agentPoolEligibility.unit.spec.ts`), menção curta em `docs/AGENT-OPS.md` / skill `agent-pool` se o contrato de labels mudar.
|
||||
- **Áreas prováveis:** `.agents/skills/plan-issue/` (SKILL + checklist Passo 5/6), `scripts/agent-register.mjs`, elegibilidade do pool (`scripts/lib/agent-pool-eligibility.mjs` + pins em `tests/unit/agentPoolEligibility.unit.spec.ts`), menção curta em `docs/AGENT-OPS.md` / skill `agent-pool` se o contrato de labels mudar.
|
||||
- **Precedente a olhar:** gate Passo 5 já escrito na skill (hoje só soft); `needs:consent` / `requirements-changed` como “não claimar”; OPS12 `plans-only-closes` (`Related #N`).
|
||||
- **Risco de acoplamento:** fila `ready` é o contrato compartilhado de `agent:claim` e do pool — mudar o momento do flip afeta os dois.
|
||||
|
||||
|
|
@ -76,8 +76,8 @@ Omitido — superfície A (processo).
|
|||
## Referências
|
||||
|
||||
- GitHub Issue #292
|
||||
- `.cursor/skills/plan-issue/SKILL.md` (Passo 5 gate / Passo 6 register)
|
||||
- `.agents/skills/plan-issue/SKILL.md` (Passo 5 gate / Passo 6 register)
|
||||
- `scripts/agent-register.mjs` (default `ready`)
|
||||
- `scripts/lib/agent-pool-eligibility.mjs` (`issueHasPlanLink` = warn)
|
||||
- `docs/AGENT-OPS.md`
|
||||
- `.cursor/skills/agent-pool/SKILL.md`
|
||||
- `.agents/skills/agent-pool/SKILL.md`
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ Omitido — superfície A.
|
|||
|
||||
## Direção no codebase (hipótese)
|
||||
|
||||
- **Áreas prováveis:** novo workflow (ou extensão cuidadosa de `issue-done-on-main-merge.yml`), helper puro testável para parse de `Related #N` + regra de promote, `.cursor/skills/plan-issue/SKILL.md` (Passo 6), nota em `docs/AGENT-OPS.md`.
|
||||
- **Áreas prováveis:** novo workflow (ou extensão cuidadosa de `issue-done-on-main-merge.yml`), helper puro testável para parse de `Related #N` + regra de promote, `.agents/skills/plan-issue/SKILL.md` (Passo 6), nota em `docs/AGENT-OPS.md`.
|
||||
- **Precedente a olhar:** `issue-done-on-main-merge.yml` (`Closes`→`done`); OPS12 `plans-only-closes`; OPS17 `#292` / `docs/plans/plan-issue-lifecycle-ready.md`.
|
||||
- **Risco de acoplamento:** flip frouxo promove Issue `blocked` por dependência de produto; misturar com o job de `Closes` sem cuidado.
|
||||
|
||||
|
|
@ -76,5 +76,5 @@ Omitido — superfície A.
|
|||
- GitHub Issue #296
|
||||
- GitHub Issue OPS17 #292
|
||||
- `.github/workflows/issue-done-on-main-merge.yml`
|
||||
- `.cursor/skills/plan-issue/SKILL.md`
|
||||
- `.agents/skills/plan-issue/SKILL.md`
|
||||
- `docs/plans/plan-issue-lifecycle-ready.md`
|
||||
|
|
|
|||
|
|
@ -40,8 +40,8 @@ Decisão de produto (2026-07-30, brief do lote CI): **done = PR mergeado em `sta
|
|||
Componentes (texto, não código):
|
||||
|
||||
- **`docs/AGENT-OPS.md`** — novo bloco na seção "Fluxo": "Dono do PR, dono do CI" (definição de done, triagem das 3 classes de falha, limite de blast radius, flaky→quarentena+débito).
|
||||
- **`.cursor/skills/work-issue/SKILL.md`** — Passo 6.5 reforçado: falha no ci-pr → corrige na mesma branch **qualquer que seja a origem**, citando AGENT-OPS; "fora do escopo" não é critério de parada.
|
||||
- **`.cursor/rules/engineering-standards.mdc`** — linha no "After every change": CI vermelho no seu PR é seu, mesmo pré-existente.
|
||||
- **`.agents/skills/work-issue/SKILL.md`** — Passo 6.5 reforçado: falha no ci-pr → corrige na mesma branch **qualquer que seja a origem**, citando AGENT-OPS; "fora do escopo" não é critério de parada.
|
||||
- **`.agents/rules/engineering-standards.mdc`** — linha no "After every change": CI vermelho no seu PR é seu, mesmo pré-existente.
|
||||
- **`docs/CHANGELOG-AGENTS.md`** — entrada do incidente PR #50 → esta política.
|
||||
|
||||
Texto-núcleo proposto (núcleo único citado nos três):
|
||||
|
|
@ -70,6 +70,6 @@ Nenhum neste item.
|
|||
## Referências
|
||||
|
||||
- Incidente: PR #50, run 30558184687 (migration-lock sem checkout; int fora da feature)
|
||||
- `docs/AGENT-OPS.md` — seção "Fluxo"; `.cursor/skills/work-issue/SKILL.md` — Passo 6
|
||||
- `.cursor/rules/engineering-standards.mdc` — "After every change"
|
||||
- `docs/AGENT-OPS.md` — seção "Fluxo"; `.agents/skills/work-issue/SKILL.md` — Passo 6
|
||||
- `.agents/rules/engineering-standards.mdc` — "After every change"
|
||||
- Issue #43 (OPS2) — harvest agent-miss → guardrails
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ Recomendação de instalação do `/campanha` como PWA, exibida no início da se
|
|||
- `docs/roadmap.md` (linhas 58, 62, 81)
|
||||
- `docs/plans/notifications.md` — push depende deste plano
|
||||
- `AGENTS.md` — Campaign auth, naming conventions, transações
|
||||
- `.cursor/rules/projects/nucleos-eleitorais.mdc`
|
||||
- `.agents/rules/projects/nucleos-eleitorais.mdc`
|
||||
- `src/app/(campaign)/layout.tsx` — root layout da vertical (onde os metadados entram)
|
||||
- `src/app/(campaign)/campanha/(app)/layout.tsx` — shell autenticado (monta o `<InstallPwaToast />`)
|
||||
- `src/components/ui/Toaster.tsx` — sonner já montado; reusar, não duplicar
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ Entregue: `MunicipalitySignalFields` + `MunicipalityListSignalControl` (Popover
|
|||
|
||||
## Design (Impeccable)
|
||||
|
||||
Âncoras: `PRODUCT.md` (princípio 2 **Clarity under pressure**, princípio 3 **Edit where you see**, princípio 4 **Auto-save, no Save button** — e a **exceção** nomeada nele para escrita atômica multi-campo, princípio 8 **Feel the action**) / `DESIGN.md` (register `product` — Field Desk) · tema `data-theme='campaign'` · regras `.cursor/rules/campanha-edit-where-you-see.mdc` (item 4: submit explícito continua válido para fluxo multi-campo) e `.cursor/rules/campanha-action-feedback.mdc` · precedentes vivos: [`MunicipalityListTrendControl.tsx`](../../src/components/campaign/municipality/MunicipalityListTrendControl.tsx) (Popover na célula) e [`MunicipalityUpdateForm.tsx`](../../src/components/campaign/municipality/MunicipalityUpdateForm.tsx) (campos do sinal tipado do C12).
|
||||
Âncoras: `PRODUCT.md` (princípio 2 **Clarity under pressure**, princípio 3 **Edit where you see**, princípio 4 **Auto-save, no Save button** — e a **exceção** nomeada nele para escrita atômica multi-campo, princípio 8 **Feel the action**) / `DESIGN.md` (register `product` — Field Desk) · tema `data-theme='campaign'` · regras `.agents/rules/campanha-edit-where-you-see.mdc` (item 4: submit explícito continua válido para fluxo multi-campo) e `.agents/rules/campanha-action-feedback.mdc` · precedentes vivos: [`MunicipalityListTrendControl.tsx`](../../src/components/campaign/municipality/MunicipalityListTrendControl.tsx) (Popover na célula) e [`MunicipalityUpdateForm.tsx`](../../src/components/campaign/municipality/MunicipalityUpdateForm.tsx) (campos do sinal tipado do C12).
|
||||
|
||||
Na implementação (`implement-roadmap-item`): craft compacto → critique → polish. Sem shape completo: a célula, o Popover de lista e o formulário de sinal já existem no produto; o que é novo é a **combinação** e a apresentação mobile (primeira vez que um controle de célula abre em bottom sheet).
|
||||
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ Componentes:
|
|||
- **`tests/unit/codebaseConventions.unit.spec.ts`**: o describe "banned campaign terminology" vira table-driven —
|
||||
`[{ id, pattern, remedy, allowlist }]` com a linha existente (Praça/Núcleo → Município, allowlist `src/lib/cities.ts`) e a nova (termo antigo da agenda → Atividade/`activity`, allowlist do próprio spec). O walker passa a percorrer `src/`, `tests/` e `scripts/`, pulando `src/migrations/`.
|
||||
- **Testes renomeados**: `tests/int/campaignActionPlan.int.spec.ts` → `campaignActivity.int.spec.ts`, `tests/unit/actionPlanUi.unit.spec.ts` → `activityUi.unit.spec.ts`, `tests/e2e/campaignActionPlan.e2e.spec.ts` → `campaignActivity.e2e.spec.ts`; `tests/helpers/campaignFixtures.ts` e `tests/e2e/fixtures/campaignE2EFixtures.ts` acompanham (inclusive a chave `action_plan_id` do cleanup de locked documents).
|
||||
- **Docs vivos**: `AGENTS.md` (seções "Campaign action plans (C3)" e a lista de collections), `.cursor/rules/codebase-map.mdc` (lista de domínios de `components/campaign`), `.cursor/rules/projects/nucleos-eleitorais.mdc` e o `docs/roadmap.md`. Planos entregues e migrations ficam como estão.
|
||||
- **Docs vivos**: `AGENTS.md` (seções "Campaign action plans (C3)" e a lista de collections), `.agents/rules/codebase-map.mdc` (lista de domínios de `components/campaign`), `.agents/rules/projects/nucleos-eleitorais.mdc` e o `docs/roadmap.md`. Planos entregues e migrations ficam como estão.
|
||||
|
||||
## Dependências
|
||||
|
||||
|
|
|
|||
|
|
@ -122,5 +122,5 @@ Componentes:
|
|||
- [sistema-listas-campanha.md](sistema-listas-campanha.md) (Pass 2 W1 — rabbit hole de generalizar o header) · [pagina-territorios-identidade.md](pagina-territorios-identidade.md) (B21 — gatilho do head genérico) · [explicacao-colunas-header-listas.md](explicacao-colunas-header-listas.md) (B22 — mesma estratégia de peça compartilhada; vizinho no mesmo `TableHead`) · [seletor-colunas-lista-municipios.md](seletor-colunas-lista-municipios.md) (B17)
|
||||
- `src/components/campaign/municipality/MunicipalityHeaderFilter.tsx`, `MunicipalityFilters.tsx` — os dois controles a alterar
|
||||
- `src/utilities/municipalityListFilters.ts`, `src/utilities/municipalityPageData.ts` (facetas) — origem e tipos das opções
|
||||
- AGENTS.md — naming (identificadores em inglês, copy pt-BR), fronteira `lib/` puro vs `utilities/` acoplado; `.cursor/rules/campanha-action-feedback.mdc` (Feel the action)
|
||||
- AGENTS.md — naming (identificadores em inglês, copy pt-BR), fronteira `lib/` puro vs `utilities/` acoplado; `.agents/rules/campanha-action-feedback.mdc` (Feel the action)
|
||||
- `PRODUCT.md` / `DESIGN.md` — Field Desk, Restrained, anti-goal de spreadsheet/data-grid
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ Artefatos do ciclo de discovery "literatura → persona → entrevista → docs
|
|||
|
||||
## Ciclo 2 — Discovery de finanças de campanha (2026-07-28)
|
||||
|
||||
Mesmo método (literatura → personas → entrevistas sintéticas → relatório → validação real), aplicado à **gestão financeira** de uma campanha de DF na Bahia, sob três ângulos (financeiro-operacional, jurídico, político). Notebook do projeto: `.cursor/rules/projects/financas-campanha.mdc`.
|
||||
Mesmo método (literatura → personas → entrevistas sintéticas → relatório → validação real), aplicado à **gestão financeira** de uma campanha de DF na Bahia, sob três ângulos (financeiro-operacional, jurídico, político). Notebook do projeto: `.agents/rules/projects/financas-campanha.mdc`.
|
||||
|
||||
| Artefato | O quê | Status |
|
||||
| ------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- |
|
||||
|
|
@ -34,7 +34,7 @@ Mesmo método (literatura → personas → entrevistas sintéticas → relatóri
|
|||
|
||||
## Ciclo 3 — Discovery de emendas parlamentares (mandato/comunicação) (2026-07-28)
|
||||
|
||||
Mesmo método (literatura → personas → entrevistas sintéticas em subagents isolados, 2 rodadas com acareação → relatório → roteiro para a sessão real), aplicado ao **registro e acompanhamento das emendas parlamentares do mandato** — a visão de produto por trás (contexto, NÃO decisão): um ledger de emendas numa vertical nova `/mandato`, consumido pela campanha (`/campanha`, ex.: dossiê de município — pedido real O6) e por uma vertical de comunicação (`/comunicacao`). Quatro ângulos: o deputado (dono político), a assessoria de orçamento (operadora da planilha), a comunicação do mandato (transforma execução em anúncio) e o coordenador de campanha (consumidor — persona ancorada na evidência real de 2026-07-23, campos [R]/[S]). Notebook do projeto: `.cursor/rules/projects/emendas-mandato.mdc`.
|
||||
Mesmo método (literatura → personas → entrevistas sintéticas em subagents isolados, 2 rodadas com acareação → relatório → roteiro para a sessão real), aplicado ao **registro e acompanhamento das emendas parlamentares do mandato** — a visão de produto por trás (contexto, NÃO decisão): um ledger de emendas numa vertical nova `/mandato`, consumido pela campanha (`/campanha`, ex.: dossiê de município — pedido real O6) e por uma vertical de comunicação (`/comunicacao`). Quatro ângulos: o deputado (dono político), a assessoria de orçamento (operadora da planilha), a comunicação do mandato (transforma execução em anúncio) e o coordenador de campanha (consumidor — persona ancorada na evidência real de 2026-07-23, campos [R]/[S]). Notebook do projeto: `.agents/rules/projects/emendas-mandato.mdc`.
|
||||
|
||||
| Artefato | O quê | Status |
|
||||
| -------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- |
|
||||
|
|
|
|||
|
|
@ -225,7 +225,6 @@ const eslintConfig = [
|
|||
'test-results/**',
|
||||
// Vendored agent material (same carve-out as .prettierignore):
|
||||
'.agents/**',
|
||||
'.cursor/**',
|
||||
]),
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ function walk(dir, out = []) {
|
|||
for (const entry of entries) {
|
||||
if (entry.name.startsWith('.') && entry.name !== '.env.test') {
|
||||
if (entry.isDirectory() && IGNORE_DIRS.has(entry.name)) continue
|
||||
if (entry.isDirectory() && entry.name !== '.github' && entry.name !== '.cursor') continue
|
||||
if (entry.isDirectory() && entry.name !== '.github' && entry.name !== '.agents') continue
|
||||
}
|
||||
if (IGNORE_DIRS.has(entry.name)) continue
|
||||
const absolute = path.join(dir, entry.name)
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ export const buildPoolWorkerPrompt = ({ issueNumber, issueTitle, issueId, planPa
|
|||
'',
|
||||
'## Fluxo',
|
||||
'',
|
||||
'Siga a skill `.cursor/skills/agent-work-issue/SKILL.md` por completo (Issue já claimada):',
|
||||
'Siga a skill `.agents/skills/agent-work-issue/SKILL.md` por completo (Issue já claimada):',
|
||||
'1. Rode `pnpm i` se `node_modules` não existir.',
|
||||
planPath
|
||||
? `2. Plano de intenção: \`${planPath}\` — abra-o; depois Plan mode e escreva \`docs/plans/<slug>-impl.md\` (engenharia deliberada; pode divergir da hipótese de direção se o aceite de produto se mantiver).`
|
||||
|
|
@ -42,7 +42,7 @@ export const buildPoolWorkerPrompt = ({ issueNumber, issueTitle, issueId, planPa
|
|||
'',
|
||||
'## Proibido',
|
||||
'',
|
||||
'- `DATABASE_URL` de prod ou `ALLOW_REMOTE_DB` — o setup local (`.cursor/cloud-setup.sh` + seed mínimo) cobre tudo.',
|
||||
'- `DATABASE_URL` de prod ou `ALLOW_REMOTE_DB` — o setup local (`.agents/cloud-setup.sh` + seed mínimo) cobre tudo.',
|
||||
`- Editar outras Issues \`in-progress\` ou trabalhar fora da Issue #${issueNumber}.`,
|
||||
'- Tratar o plano de intenção como contrato de engenharia — ele é intenção; o `*-impl.md` é a engenharia.',
|
||||
'',
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ type SaveMunicipalityFilterControlProps = {
|
|||
* Names the current recorte and keeps it in the sidebar (B18).
|
||||
*
|
||||
* Naming is confirmatory, so this is the explicit-submit exception
|
||||
* `.cursor/rules/campanha-edit-where-you-see.mdc` already carves out for flows
|
||||
* `.agents/rules/campanha-edit-where-you-see.mdc` already carves out for flows
|
||||
* that need a note — and it keeps this control out of the auto-save machine the
|
||||
* quick-edit cells share.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1098,6 +1098,7 @@ export class CampaignFixtures {
|
|||
levelNote: null,
|
||||
strengths: [],
|
||||
risks: [],
|
||||
stateDeputies: [],
|
||||
dobradinhaNotes: null,
|
||||
nextSteps: null,
|
||||
lastUpdateAt: null,
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ describe('plansOnlyClosesGuard', () => {
|
|||
expect(isPlansOnlyDiff(['docs/plans/bottom-drawer-peek-acoes-busca.md'])).toBe(true)
|
||||
expect(isPlansOnlyDiff([])).toBe(false)
|
||||
expect(isPlansOnlyDiff(['docs/plans/a.md', 'docs/plans/sub/b.md'])).toBe(true)
|
||||
expect(isPlansOnlyDiff(['docs/plans/a.md', '.cursor/skills/plan-issue/SKILL.md'])).toBe(false)
|
||||
expect(isPlansOnlyDiff(['docs/plans/a.md', '.agents/skills/plan-issue/SKILL.md'])).toBe(false)
|
||||
})
|
||||
|
||||
it('finds closing keywords case-insensitively', () => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue