diff --git a/docs/plans/lembranca-status-liderancas-impl.md b/docs/plans/lembranca-status-liderancas-impl.md new file mode 100644 index 00000000..c1730d4a --- /dev/null +++ b/docs/plans/lembranca-status-liderancas-impl.md @@ -0,0 +1,89 @@ +# Impl: Status de apoio "Lembrança" em lideranças + +Status: em execução +Atualizado em: 2026-08-11 +Issue: #661 +Intenção: docs/plans/lembranca-status-liderancas.md +Appetite restante: herdado (~1 dia eng) — item pequeno, cabe folgado + +## Leitura da intenção + +- **Outcome:** novo valor `lembranca` no enum `supportStatus` de `leadership` (entre `em_disputa` e `negativo` no seletor), visível e marcável em TODAS as superfícies onde os 4 status atuais aparecem (célula da lista com auto-save, ficha/wizard/admin, filtro das listas de lideranças e de pessoas, Sollinha); **nunca** entra no critério de pendência de abordagem (fail-closed na query, não só na UI); badge visualmente distinto; nenhuma leitura existente quebra. +- **O que NÃO negociar:** liderança "Lembrança" é favorável e não é pendente — exclusão das pendências espelhando o "Negativo" (na query `getPendingLeaderships`, que já é fail-closed); sem segundo eixo de classificação; sem fluxo próprio de votos (usa o campo de votos declarados existente); leader lockdown intacto (status é staff-only). +- **O que reavaliar:** a hipótese da intenção cobre as áreas certas, mas encontrei duas superfícies que ela não nomeou: (1) `peopleData.ts` `leadershipStatusesInOrder` — lista dura dos 4 valores que **silenciosamente omitiria** o novo status do facet da lista de pessoas; (2) `getLeaderships.ts` mantém uma tabela de rótulos duplicada (`SUPPORT_LABELS`) que também esqueceria o valor novo — candidata a DRY com `supportStatusLabels`. + +## Abordagem recomendada + +```mermaid +flowchart LR + A[leadershipSupportStatuses\n+ 'lembranca'] --> B[collection options\n+ migration ALTER TYPE] + A --> C[labels + badge variant\n+ tokens CSS] + A --> D[listas/filtros/forms\nvia enum array] + A --> E[getLeaderships usa\nsupportStatusLabels] + F[getPendingLeaderships\nINTOCADO + teste pin] --> G[pendências excluem\nlembranca fail-closed] + H[systemPrompt +1 linha\nreconhecimento] --> I[Sollinha responde\nsobre o status] +``` + +**Opções consideradas:** A (valor novo no enum existente, fonte única) | B (segundo campo/eixo de classificação) | C (status composto em string) +**Recomendação:** A — o produto decidiu no gate que é um valor a mais no enum; a engenharia tem um único source of truth (`leadershipSupportStatuses` + `supportStatusLabels`) e as superfícies que derivam dele (listas, forms, URLs, omnibox) ganham o valor automaticamente. +**Rejeitadas:** B porque a intenção corta explicitamente o segundo eixo (matriz de combinações); C porque destrói filtro `in` no Postgres e indexação. + +### Decisões de engenharia + +- **D1 — Migration do enum.** `ALTER TYPE "public"."enum_leadership_support_status" ADD VALUE 'lembranca' BEFORE 'negativo'` — o `BEFORE` preserva a ordem do enum no Postgres igual à do seletor (decisão do gate: entre "Em disputa" e "Negativo"), então `sort: 'supportStatus'` na lista ordena igual ao seletor. + - _Rejeitadas:_ `ADD VALUE` sem `BEFORE` (anexa no fim → ordenação por status divergiria do seletor); recriar o tipo inteiro (rename+create+cast, precedente C14) — destrutivo demais para um valor novo, risco desnecessário em prod. + - Precedentes: `20260723_025513` (ADD VALUE … BEFORE), `20260728_041547` / `20260724_180000` (ADD VALUE). Se o `migrate:create` gerar `ADD VALUE` sem `BEFORE`, editar o `.ts` da migration nova (migration não shipada — editável; nunca editar as antigas). +- **D2 — Badge distinto.** Novo variant `support-remembered` no `Badge` + tokens `--support-remembered`/`-foreground` (índigo suave: `#e0e7ff` / `#3730a3`) — distinto dos 4 atuais (verde/cinza/âmbar/vermelho) e semanticamente "resolvido e favorável". + - _Rejeitadas:_ reusar `estimate-*` (âmbar colide com "Em disputa"); variant `default` (não distinto). +- **D3 — `getLeaderships.ts`: matar a tabela duplicada.** Substituir `SUPPORT_LABELS` por `supportStatusLabels` de `leadershipLabels.ts` (tabela de strings pura, client-safe, importável do server). Um valor novo no enum seria propagado pela fonte única em vez de exigir lembrar da duplicata. + - _Rejeitada:_ só adicionar `lembranca` na duplicata — deixa a segunda fonte de verdade viva para o próximo status. +- **D4 — `peopleData.ts` `leadershipStatusesInOrder`:** trocar a lista dura `['engajado','a_abordar','em_disputa','negativo']` por `leadershipSupportStatuses.filter(s => statuses.has(s))`. Sem isso o status novo não apareceria no facet da lista de pessoas (miss silencioso, sem teste pegando). +- **D5 — Pendência: não tocar.** `PENDING_SUPPORT_STATUSES = ['a_abordar','em_disputa','engajado']` e `PENDING_CRITERION` ficam como estão — "Lembrança" e "Negativo" já são excluídos pela ausência da lista (fail-closed na query) e o critério declarado continua sem o novo estado (aceite: "pendências declaram o critério sem o novo estado"). Adicionar teste que pin a exclusão. +- **D6 — Sollinha reconhece o status:** +1 linha na seção "Lideranças pendentes de abordagem" do `systemPrompt.ts` (ex.: "Liderança com status 'Lembrança' é favorável sem compromisso — não conta como pendente de abordagem"). O rótulo na leitura vem de D3. +- **Semânticas que excluem "Lembrança" intencionalmente (verificar com testes, não mudar):** convite de login exige `engajado` (`campaignInvite*`), acesso ao app exige `engajado` (`access/contacts.ts`, `access/municipalities.ts`), opção de "responsável" de atividade exige `engajado` (`activityLeadershipOptions.ts`) — uma "Lembrança" não é engajada, comportamento correto. + +### Componentes / mudanças + +- **`leadershipSupportStatuses`** (`src/lib/schemas/leadership.ts`): `['engajado', 'a_abordar', 'em_disputa', 'lembranca', 'negativo']` — tipo `SupportStatus` e `isSupportStatus` derivam sozinhos. +- **`Leadership.ts`** (collection): opção `{ label: 'Lembrança', value: 'lembranca' }` na posição 4 (admin select + admin filter automáticos). +- **Migration:** `add_lembranca_support_status` via `pnpm migrate:create`, SQL conforme D1. +- **`payload-types.ts`:** regenerar via `pnpm generate:types`. +- **`leadershipLabels.ts`:** `lembranca: 'Lembrança'`. +- **`SupportStatusBadge.tsx`:** `lembranca: { variant: 'support-remembered' }`. +- **`Badge.tsx`** + **`styles.css`:** variant e tokens (D2). +- **`getLeaderships.ts`:** `SUPPORT_LABELS` → `supportStatusLabels` (D3). +- **`systemPrompt.ts`:** linha de reconhecimento (D6). +- **`peopleData.ts`:** `leadershipStatusesInOrder` via enum canônico (D4). +- **Automático (sem edição):** `LeadershipListSupportStatusControl`, `LeadershipForm`/`LeadershipInternalForm`/`WizardLeadershipForm`, `leadershipListFilters`/`peopleListFilters`, `leadershipListUrl`/`peopleListUrl` (parse enum exaustivo), omniboxes, `leadershipData`, `wizardLeadershipContract`, `municipalityV2Network*`, actions/routes zod (`z.enum(leadershipSupportStatuses)`), `support-status/route.ts`. +- **Access / Consent:** nenhum — status é staff-only (`canManageCampaignStaffField`), leader lockdown intocado. + +### Dados → forma + +Não se aplica (nenhuma superfície de dado nova; valor de enum flui por filtros/facets existentes — decisão de produto do gate). + +## Fases verificáveis + +1. **Schema+server** — enum array + collection options + migration + `generate:types`; verificação: `pnpm migrate:status` e `pnpm migrate` local. +2. **UI** — labels + Badge + tokens + `SupportStatusBadge`; verificação: badge unit test (it.each) renderiza `Lembrança`. +3. **IA + pessoas** — `getLeaderships` DRY, `systemPrompt`, `peopleData` ordem; verificação: testes de tool e listas. +4. **Testes** — atualizar os que enumeram status (badge it.each, "every status member" do `leadershipListUrl`, fixture e2e, int spec com `lembranca` persistindo, pin de exclusão de pendência); NENHUM teste novo de feature em volume. +5. **Gates** — `tsc --noEmit`, `pnpm lint`, `pnpm format:check`, `pnpm exec knip`, `pnpm check:cycles`, `pnpm test`, `pnpm build` local. + +## Rabbit holes / Não escopo (engenharia) + +- Migração destrutiva do enum (recreate) — desnecessária com `BEFORE`. +- Reordenar `a_abordar` no seletor — produto não pediu. +- Tratamento especial de votos para "Lembrança" — decidido no gate: campo de votos declarados já existente. +- Qualquer mudança em convites/acesso-app/atividade (engajado-only é o comportamento correto). + +## Riscos e mitigação + +- **Migration `ADD VALUE` + transação Postgres:** permitido desde PG 12 dentro de transação (novo valor não usado na mesma transação); precedente shipado em prod (`20260723_025513`). Mitigação: verificar `pnpm migrate` local e `migrate:status` antes do push. +- **Superfície enumerada esquecida:** mitigado por D3/D4 (fonte única) + teste de badge it.each + teste "every status member" da URL. +- **Filtro `lembranca` vazando para pendências:** fail-closed já está na query; o teste unit do `getPendingLeaderships` passa a incluir `lembranca` na exclusão pinada. + +## Aceite de engenharia + +- [x] Aceite de produto da intenção ainda coberto (superfícies todas + pendências excluem + badge distinto + Sollinha reconhece) +- [x] Invariantes AGENTS/engineering-standards (sem transações novas, sem access novo, nomes EN, rótulos pt-BR) +- [x] Testes de domínio previstos (badge it.each, URL enum exaustivo, pin pendência, int persistence) diff --git a/src/app/(frontend)/styles.css b/src/app/(frontend)/styles.css index 432c6e1a..7f6161a0 100644 --- a/src/app/(frontend)/styles.css +++ b/src/app/(frontend)/styles.css @@ -72,6 +72,8 @@ body, --color-support-to-approach: var(--support-to-approach); --color-support-disputed-foreground: var(--support-disputed-foreground); --color-support-disputed: var(--support-disputed); + --color-support-remembered-foreground: var(--support-remembered-foreground); + --color-support-remembered: var(--support-remembered); --color-support-negative-foreground: var(--support-negative-foreground); --color-support-negative: var(--support-negative); --color-estimate-confirmed-foreground: var(--estimate-confirmed-foreground); @@ -249,6 +251,8 @@ body, --support-to-approach-foreground: #46505c; --support-disputed: #fef3c7; --support-disputed-foreground: #92400e; + --support-remembered: #e0e7ff; + --support-remembered-foreground: #3730a3; --support-negative: #fee2e2; --support-negative-foreground: #991b1b; --estimate-confirmed: #dcfce7; diff --git a/src/collections/Leadership.ts b/src/collections/Leadership.ts index cc858e20..4105ac37 100644 --- a/src/collections/Leadership.ts +++ b/src/collections/Leadership.ts @@ -146,6 +146,7 @@ export const Leadership: CollectionConfig = { { label: 'Engajado', value: 'engajado' }, { label: 'A abordar', value: 'a_abordar' }, { label: 'Em disputa', value: 'em_disputa' }, + { label: 'Lembrança', value: 'lembranca' }, { label: 'Negativo', value: 'negativo' }, ], }, diff --git a/src/components/campaign/leadership/SupportStatusBadge.tsx b/src/components/campaign/leadership/SupportStatusBadge.tsx index c849d01b..b892a259 100644 --- a/src/components/campaign/leadership/SupportStatusBadge.tsx +++ b/src/components/campaign/leadership/SupportStatusBadge.tsx @@ -10,6 +10,7 @@ const statusPresentation = { engajado: { variant: 'support-engaged' }, a_abordar: { variant: 'support-to-approach' }, em_disputa: { variant: 'support-disputed' }, + lembranca: { variant: 'support-remembered' }, negativo: { variant: 'support-negative' }, } as const diff --git a/src/components/ui/Badge.tsx b/src/components/ui/Badge.tsx index 5d2b2a67..dd92fbad 100644 --- a/src/components/ui/Badge.tsx +++ b/src/components/ui/Badge.tsx @@ -24,6 +24,8 @@ const badgeVariants = cva( 'bg-support-to-approach text-support-to-approach-foreground [a]:hover:bg-support-to-approach/80', 'support-disputed': 'bg-support-disputed text-support-disputed-foreground [a]:hover:bg-support-disputed/80', + 'support-remembered': + 'bg-support-remembered text-support-remembered-foreground [a]:hover:bg-support-remembered/80', 'support-negative': 'bg-support-negative text-support-negative-foreground [a]:hover:bg-support-negative/80', 'estimate-confirmed': diff --git a/src/lib/schemas/leadership.ts b/src/lib/schemas/leadership.ts index 230ccfdc..6a3aaa5f 100644 --- a/src/lib/schemas/leadership.ts +++ b/src/lib/schemas/leadership.ts @@ -14,6 +14,7 @@ export const leadershipSupportStatuses = [ 'engajado', 'a_abordar', 'em_disputa', + 'lembranca', 'negativo', ] as const diff --git a/src/migrations/index.ts b/src/migrations/index.ts index b2f81972..20ef82c5 100644 --- a/src/migrations/index.ts +++ b/src/migrations/index.ts @@ -47,8 +47,7 @@ import * as migration_20260808_134911_add_calendar_feed from './20260808_134911_ import * as migration_20260808_184113_remodel_activity_responsible from './20260808_184113_remodel_activity_responsible'; import * as migration_20260809_204728_add_campaign_user_contact_and_leadership_advisors from './20260809_204728_add_campaign_user_contact_and_leadership_advisors'; import * as migration_20260810_010844_add_activity_all_day from './20260810_010844_add_activity_all_day'; -import * as migration_20260811_111828_add_contact_phones_array from './20260811_111828_add_contact_phones_array'; -import * as migration_20260811_133332_add_google_calendar_sync from './20260811_133332_add_google_calendar_sync'; +import * as migration_20260811_153004_add_lembranca_support_status from './20260811_153004_add_lembranca_support_status'; export const migrations = [ { @@ -297,13 +296,8 @@ export const migrations = [ name: '20260810_010844_add_activity_all_day', }, { - up: migration_20260811_111828_add_contact_phones_array.up, - down: migration_20260811_111828_add_contact_phones_array.down, - name: '20260811_111828_add_contact_phones_array', - }, - { - up: migration_20260811_133332_add_google_calendar_sync.up, - down: migration_20260811_133332_add_google_calendar_sync.down, - name: '20260811_133332_add_google_calendar_sync', + up: migration_20260811_153004_add_lembranca_support_status.up, + down: migration_20260811_153004_add_lembranca_support_status.down, + name: '20260811_153004_add_lembranca_support_status' }, ]; diff --git a/src/payload-types.ts b/src/payload-types.ts index 37bf8da5..4ed0842c 100644 --- a/src/payload-types.ts +++ b/src/payload-types.ts @@ -590,7 +590,7 @@ export interface Leadership { stateDeputies?: (number | StateDeputy)[] | null; advisors?: (number | CampaignUser)[] | null; exclusive?: boolean | null; - supportStatus: 'engajado' | 'a_abordar' | 'em_disputa' | 'negativo'; + supportStatus: 'engajado' | 'a_abordar' | 'em_disputa' | 'lembranca' | 'negativo'; user?: (number | null) | CampaignUser; consent?: (number | null) | Consent; consentContentHash?: string | null; diff --git a/src/utilities/ai/systemPrompt.ts b/src/utilities/ai/systemPrompt.ts index 1b3aa36a..037330e0 100644 --- a/src/utilities/ai/systemPrompt.ts +++ b/src/utilities/ai/systemPrompt.ts @@ -43,6 +43,7 @@ export const AI_SYSTEM_PROMPT = `Você é o Sollinha, assistente virtual da camp ## Lideranças pendentes de abordagem - Use a ferramenta "getPendingLeaderships" para "quais lideranças ainda precisam ser abordadas em X", "lideranças sem assessor responsável" ou "quais municípios não têm liderança cadastrada". - A resposta da ferramenta traz o critério de pendência — declare-o sempre na sua resposta (ex.: "critério: status 'A abordar' ou 'Em disputa'; ou 'Engajado' sem compromisso de votos no escopo consultado"). +- Liderança com status "Lembrança" é favorável sem compromisso — não conta como pendente de abordagem; se perguntarem, explique isso e, se houver, aponte essas lideranças pela leitura normal de lideranças. - Escopos: território de identidade (aceita grafia sem acento, ex.: "Vale do Jiquiriça"), cidade ("Salvador" = as 19 zonas eleitorais juntas) ou município. Sem escopo, vale o escopo de acesso do usuário. - Quando a resposta trouxer "escopoRestrito: true", deixe claro que os resultados estão limitados aos municípios do portfólio do usuário; quando trouxer "truncado: true", sugira estreitar o escopo para ver o restante. - Ofereça links de navegação (buildCampaignLinks) para as lideranças citadas (por id) e municípios (por slug); assessores (por id) quando o perfil permitir. diff --git a/src/utilities/ai/tools/getLeaderships.ts b/src/utilities/ai/tools/getLeaderships.ts index 6d647337..36f7c5b4 100644 --- a/src/utilities/ai/tools/getLeaderships.ts +++ b/src/utilities/ai/tools/getLeaderships.ts @@ -3,13 +3,7 @@ import type { Where } from 'payload' import { z } from 'zod' import type { AIToolContext } from '@/lib/ai/types' - -const SUPPORT_LABELS: Record = { - engajado: 'Engajado', - a_abordar: 'A abordar', - em_disputa: 'Em disputa', - negativo: 'Negativo', -} +import { supportStatusLabels } from '@/utilities/leadership/leadershipLabels' export const getLeaderships = (ctx: AIToolContext) => tool({ @@ -67,7 +61,8 @@ export const getLeaderships = (ctx: AIToolContext) => organizacoes: organizations.map((o) => o.name), apoioExclusivo: doc.exclusive === true, status: - SUPPORT_LABELS[(doc.supportStatus as string) ?? ''] ?? (doc.supportStatus as string), + supportStatusLabels[doc.supportStatus as keyof typeof supportStatusLabels] ?? + (doc.supportStatus as string), observacoes: (doc.notes as string) ?? null, } }) diff --git a/src/utilities/leadership/leadershipLabels.ts b/src/utilities/leadership/leadershipLabels.ts index 4842cc10..2cb825a0 100644 --- a/src/utilities/leadership/leadershipLabels.ts +++ b/src/utilities/leadership/leadershipLabels.ts @@ -8,6 +8,7 @@ export const supportStatusLabels: Record = { engajado: 'Engajado', a_abordar: 'A abordar', em_disputa: 'Em disputa', + lembranca: 'Lembrança', negativo: 'Negativo', } diff --git a/src/utilities/people/peopleData.ts b/src/utilities/people/peopleData.ts index c8edfeaa..471163d5 100644 --- a/src/utilities/people/peopleData.ts +++ b/src/utilities/people/peopleData.ts @@ -4,7 +4,11 @@ import type { Payload } from 'payload' import { primaryPhoneOf } from '@/lib/phone' import { relationshipId, uniqueRelationshipIds } from '@/lib/relationship' -import { isSupportStatus, type SupportStatus } from '@/lib/schemas/leadership' +import { + isSupportStatus, + leadershipSupportStatuses, + type SupportStatus, +} from '@/lib/schemas/leadership' import type { CampaignUser, Contact, Leadership, StateDeputy } from '@/payload-types' import { municipalityIdsByAdvisorIds } from '@/utilities/advisorData' import { getAdvisorMunicipalityIds, isCampaignStaff } from '@/utilities/campaignAccess' @@ -275,9 +279,7 @@ export const peopleFilterFacetsFromRows = ( } const leadershipStatusesInOrder = (statuses: ReadonlySet): SupportStatus[] => - (['engajado', 'a_abordar', 'em_disputa', 'negativo'] as const).filter((status) => - statuses.has(status), - ) + leadershipSupportStatuses.filter((status) => statuses.has(status)) const EMPTY_FACETS: PeopleListFilterFacets = { municipalityIDs: [], statuses: [] } diff --git a/tests/e2e/fixtures/campaignE2EFixtures.ts b/tests/e2e/fixtures/campaignE2EFixtures.ts index 2abf4c51..1f3a93ae 100644 --- a/tests/e2e/fixtures/campaignE2EFixtures.ts +++ b/tests/e2e/fixtures/campaignE2EFixtures.ts @@ -183,7 +183,7 @@ export class CampaignE2EOwnership { }: { namePrefix: string municipalities: { id: number; name: string }[] - supportStatus?: 'a_abordar' | 'em_disputa' | 'engajado' | 'negativo' + supportStatus?: 'a_abordar' | 'em_disputa' | 'lembranca' | 'engajado' | 'negativo' user?: number }): Promise<{ contactName: string; contactId: number; leadershipId: number }> { const contactName = this.value(namePrefix) diff --git a/tests/int/campaignLeadership.int.spec.ts b/tests/int/campaignLeadership.int.spec.ts index e60b9857..7274493e 100644 --- a/tests/int/campaignLeadership.int.spec.ts +++ b/tests/int/campaignLeadership.int.spec.ts @@ -427,6 +427,27 @@ describe('campaign leadership domain', () => { ).rejects.toThrow() }) + it('persists the "lembranca" support status through create and internal update (C119)', async () => { + const coordinator = await campaignFixtures().createCampaignUser('coordinator') + const municipality = await campaignFixtures().getMunicipality() + + const created = await createLeadershipRecord(payload, coordinator, { + municipalities: [municipality.id], + name: 'Liderança Lembrança', + phone: campaignFixtures().phone(), + supportStatus: 'lembranca', + }) + + const doc = await payload.findByID({ collection: 'leadership', id: created.id, depth: 0 }) + expect(doc.supportStatus).toBe('lembranca') + + const updated = await updateLeadershipInternalRecord(payload, coordinator, { + id: created.id, + supportStatus: 'lembranca', + }) + expect(updated.supportStatus).toBe('lembranca') + }) + it('denies leadership creation to leader accounts', async () => { const leader = await campaignFixtures().createCampaignUser('leader') const municipality = await campaignFixtures().getMunicipality() diff --git a/tests/unit/campaignComponents.unit.spec.ts b/tests/unit/campaignComponents.unit.spec.ts index 800fed71..850751f0 100644 --- a/tests/unit/campaignComponents.unit.spec.ts +++ b/tests/unit/campaignComponents.unit.spec.ts @@ -188,6 +188,7 @@ describe('campaign visual foundation', () => { ['engajado', 'Engajado'], ['a_abordar', 'A abordar'], ['em_disputa', 'Em disputa'], + ['lembranca', 'Lembrança'], ['negativo', 'Negativo'], ] as const)('renders the %s support status with text and semantic state', (status, label) => { const html = renderToStaticMarkup(createElement(SupportStatusBadge, { status })) diff --git a/tests/unit/leadershipListUrl.unit.spec.ts b/tests/unit/leadershipListUrl.unit.spec.ts index 90d5877d..30ccf7aa 100644 --- a/tests/unit/leadershipListUrl.unit.spec.ts +++ b/tests/unit/leadershipListUrl.unit.spec.ts @@ -63,7 +63,7 @@ describe('leadership list URL contract', () => { it('canonicalizes selecting every status member to the absent filter (B18)', () => { expect( parseLeadershipListParams({ - status: ['engajado', 'a_abordar', 'em_disputa', 'negativo'], + status: ['engajado', 'a_abordar', 'em_disputa', 'lembranca', 'negativo'], }), ).toEqual({ page: 1 }) }) diff --git a/tests/unit/pendingLeadershipsTool.unit.spec.ts b/tests/unit/pendingLeadershipsTool.unit.spec.ts index 43af73cf..19ded2f4 100644 --- a/tests/unit/pendingLeadershipsTool.unit.spec.ts +++ b/tests/unit/pendingLeadershipsTool.unit.spec.ts @@ -86,7 +86,7 @@ describe('getPendingLeaderships gate (B185)', () => { }) describe('getPendingLeaderships pending criterion (B185)', () => { - it('lists a_abordar/em_disputa e engajado sem pledge; exclui engajado com pledge e qualquer negativo', async () => { + it('lists a_abordar/em_disputa e engajado sem pledge; exclui engajado com pledge, qualquer negativo e qualquer lembranca (C119)', async () => { const find = vi.fn() find.mockResolvedValueOnce( findResult([ @@ -95,6 +95,7 @@ describe('getPendingLeaderships pending criterion (B185)', () => { leadershipDoc({ id: 3, supportStatus: 'em_disputa' }), leadershipDoc({ id: 4, supportStatus: 'engajado' }), leadershipDoc({ id: 5, supportStatus: 'negativo' }), + leadershipDoc({ id: 6, supportStatus: 'lembranca' }), ]), ) find.mockResolvedValueOnce(findResult([{ leadership: 2 }]))