- PEOPLE_ABSENCES ganha o 4º valor qualquer_ausencia ("Qualquer ausência"),
a união exata das três ausências em UM chip — o 3º clique dos específicos
deixa de colapsar o facet (3 de 4 membros) e o parse absorve o guarda-chuva
sobre os específicos, sem tocar no B18 genérico de capacity/status
- peopleListSortPrimaryOptions: seeds do grupo Ordenação viram as 7 direções
primárias com emptyQueryVisible, então o mobile descobre as 7 chaves ao
tocar no bar (e "ordenar" não corta aliada/assessorado/base no cap 8)
- CampaignListOmnibox reabre o popover no mousedown: clicar num input já
focado (logo após commitar busca com Enter) não disparava focus, deixando
a descoberta morta no mobile até digitar
- tests: contrato de URL (absorção + não-colapso), predicado + AND, novo spec
de omnibox, e2e do 3º clique e da descoberta mobile (390×844)
O commit OPS33 (f0f5b73f) entrou com o arquivo já conflitado na região do
bullet 'Per-worktree environments' (<<<<<<< HEAD indentado + lado HEAD
pré-OPS33 com artefato '- # ' + fechamento corrompido '> > > > > > >'; o
======= foi removido no próprio commit) e o OPS37 herdou o estado.
Resolução perda zero validada por diff: manter o lado superset (OPS28 +
OPS31 + OPS33 — claim determinístico, --issue N, prompt citado) e
descartar o lado HEAD; -3 linhas no total; scan de todos os trackeados
confirmou AGENTS.md como único arquivo afetado.
Guardrail: describe 'no conflict markers in committed files' em
codebaseConventions.unit.spec.ts — varre git ls-files e falha em
<<<<<<< / >>>>>>> (tolerante a indentação) e na forma corrompida
^\s*(> ){7}; validado negativo contra o estado sujo (AGENTS.md:37, 40).
next dev resolve a porta antes de @next/env carregar env-files (commander
.env('PORT') no bin/next), então o PORT=3100+slot do provisionador de
worktree era ignorado e todo dev server subia em 3000. pnpm dev/devsafe
passam por scripts/dev.mjs: preflight do guard-dev-db inline, env com a
mesma precedência (real > .env.local > .env, override:false) e porta como
flag CLI -p (resolveDevPort/nextDevArgs em scripts/lib/cli.mjs,
unit-testados). Sem PORT → nenhum -p → default 3000 + allowRetry intactos.
O renderer de links do chat decide interno vs externo (B187/B188); a decisão
pura de fechamento mora no owner src/lib/ai/markdownLinks.ts
(shouldCloseDrawerOnLinkClick: interno && mobile && clique simples) e o
markdownComponents estatico virou useMemo no corpo do CampaignAIChat para
alcancar o contexto. Desktop inalterado; links externos/modos de nova aba
mantem o drawer da aba de origem; sessao e restore intactos (close persiste
open:false).
- unit: 12 testes da decisao pura
- e2e (modo CI, E2E_PROD=1): interno fecha + navega sem load + reload nao
reabre; externo abre popup e mantem o drawer
- debito B199/#672 (depends #660): race de persistencia ao fechar mid-stream
Espelho oficial da agenda em calendário Google compartilhado via API
(service account, jose + fetch): reconciliação por passada com id
determinístico teqo+base32hex (upsert idempotente, sem estado por evento),
hooks afterChange/afterDelete na activity (só campos espelhados, nunca
lança), auto-resync quando calendarId muda, retry na view da agenda,
pill de estado no header + FAB + diálogo (4 estados). Cancelado no Teqo
deleta o evento no Google. Sem participantes no v1 (decisão de produto).
Sem migration nova de tabela (hand-written). Closes#635
- sort/dir/ausencia no contrato de URL de /campanha/pessoas (molde territórios/B15)
- sortPeopleRows sobre o conjunto filtrado, nulls no fim, tiebreak nome→contactID
- PeopleSortableHead (CampaignSortableHead) com aria-sort nas 7 colunas visíveis
- omnibox: grupo Ordenação (chave×direção) e facet Ausência (Sem assessor/base/contato)
- clear preserva o sort; tests unit + e2e; sem migration/collection
D12 (#641): strict-mode violation (2 triggers idênticos) só em runs
completos sob carga. Estado estável tem 1 match (verificado em browser);
o 2º match é duplicação transitória RSC-pending, mesma classe de cd469857.
Mesmo alvo em campaignActivity:52 (único outro uso do label em e2e).
- Contact.phone (text único) → phones (array field Payload, subcampo value):
fonte única; principal = phones[0]; beforeValidate normaliza, filtra vazios,
rejeita inválido e duplicado DENTRO da ficha (C111 entre fichas preservado)
- migration add_contact_phones_array: backfill phone → phones[0] (gen_random_uuid)
antes do drop da coluna + índice em value (hand-edit documentado; snapshot .json
gerado mantém as colunas C99/C100 já existentes)
- primaryPhoneOf / phoneValuesOf / reorderWithPrimaryPhone em src/lib/phone.ts
(ordem = prioridade; inline edit = seta o principal preservando o resto)
- findOrCreateContactByPhone aceita phones[] (dedupe pelo primário; reuse faz
append dos faltantes; locks em todos os números digitados)
- sync conta→ficha (CampaignUser): phone da conta faz APPEND quando a ficha não
tem (nunca reordena nem remove); tombstone LGPD substitui TODOS os telefones
- convite redemption: telefone digitado vira principal, demais preservados
- import CSV: preview sinaliza compartilhado também por número secundário;
bulk insere contact_phones (JOIN nas leituras, uuid no insert)
- busca por telefone (apoiadores, pickers, combobox) casa qualquer número
- UI: PhonesFieldEditor compartilhado (repetível mascarado, remover, ↑/↓,
modo inline com Salvar) nas 5 superfícies — liderança (form/ficha/lista),
apoiador (form/ficha), dobradinha (ficha), assessor (ficha), wizard
- UI pública (petição/WhatsApp) intocada: zod e forms ficam com phone;
as ações mapeiam phone → phones[0]
- testes: spec novo campaignMultiPhones (aceite completo), specs C111/C99
atualizados, e2e wizard/apoiador ajustados
- Sessão por arquivo: coordinator/leader compartilhados por worker (ownership
própria, cleanup no afterAll); beforeEach semeia o cookie campaign-token no
context fresh de cada teste; advisors permanecem por teste (OPS29/B176)
- Premissa da intenção corrigida por medição: getPayload é memoizado por
worker (364 ms cold, 0 ms warm); o overhead real era login de browser
(3.6 s quente / 30.3 s 1º hit vs 112-134 ms de seed) + criação de usuário
- Sem mode: 'serial' (divergência declarada): seed por cookie dispensa o
reuso de contexto e evita skips em cascata no relatório
- Endurece 7 interações client-side com toPass (classe B13/B17 exposta pela
remoção do warm-up do login) e 4 lookups do strip de ações com .first()
(duplicado transitório RSC)
- Medição antes/depois registrada no CHANGELOG; débito OPS39 (prewarm de
home-search/mudar-tendencia) registrado com depends no OPS30