# Preferências do Inbox, reserva de variável e próxima ação

Adaptação dos PRs #3402 e #3405, de @xxfabioxx12, e #3458, de @webtecnica.
Os commits originais permanecem ancestrais dos merges. Destino: núcleo. São
preferências e renderizadores da operação comum, usados sem extensões ativas.

## Contratos preservados

O Inbox lembra somente número e Não lidos neste navegador, por organização.
Busca e etiqueta continuam como antes. A restauração pós-hidratação associa o
estado à organização antes de permitir gravação; a consulta não recebe o número
do contexto anterior enquanto a organização troca. Canais ainda carregando não
invalidam a preferência; número que saiu da lista continua identificado pelo
controle existente. Armazenamento indisponível permite usar o filtro na visita.

`{{primeiro_nome|"aluno"}}` usa a reserva quando falta o dado. Com o dado presente,
ele vence. A sintaxe compartilhada mantém as restrições da fonte: aspas retas ou
curvas, de 1 a 100 caracteres, sem chaves nem aspas internas. Sintaxe inválida
fica literal. Campanha e Inbox preservam variáveis desconhecidas como literais;
a automação mantém seu resolvedor de caminhos e campos personalizados. A reserva
não cria um resolvedor novo nem muda tokens sem `|`. O nome interno da agenda
continua excluído do render das automações.

`proximaAcaoGenerica` reconhece uma lista curta de frases de resposta sem
conteúdo. Não avalia toda ação nem exige prazo por schema. A chamada continua
podendo atualizar os demais campos; só essa próxima ação é descartada, com
orientação devolvida ao modelo. Uma proposta anterior e sua sequência ficam
como estavam; uma ação concreta e `null` continuam reescrevendo a proposta.
Frases antigas já gravadas não são limpas por esta mudança.

## Medições locais

O teste do `InboxLayout` real, com serviços e filhos dublados, observou dois
vermelhos: a restauração gravava o valor inicial sobre a preferência; trocar de
A para B gravava o número de A na memória de B. Os controles de desligar e de
armazenamento bloqueado passavam. Essa prova mede os efeitos React, não UX.

Depois da correção, os testes dirigidos dos três PRs e consumidores passaram.
`inbox-filters-scope.test.tsx` também mede o controle real de número removido e
a lista ainda carregando; a prova dos efeitos fica separada dessa camada.
As sabotagens isoladas da reserva e do descarte da frase reproduziram as falhas
previstas, com restauração dos bytes conferida por hash.

## Provas de navegador preparadas

**Estado: primeira execução real reprovada; reparo aguarda nova execução.** O
run `40436794921`, head `2e043f462face49a58df6fdd02cf3e00f5d423fc`, encontrou
quatro falhas nas partes 5 e 6. Os artefatos mostram o seletor de organização
corretamente oculto para quem tem só uma empresa, o seletor de número oculto
após a fixture deixar apenas um canal, e o import do motor recusado pelo loader
do Playwright. Não são prova de UX concluída. As capturas são gravadas em `evidence/antigos-core-*`, para a coleta
existente do CI preservá-las também em sucesso.

| Caso existente estendido | O que o novo caso deve medir |
| --- | --- |
| `inbox-busca-e-filtros-dizem-a-verdade.spec.ts` | Escolher número e Não lidos, recarregar, A/B/A com preferências distintas, número removido, desligar sem afetar A, armazenamento bloqueado. Login e consultas reais; organizações e canais próprios, removidos no fim. |
| `qa-l12-inbox.spec.ts` | Criar resposta rápida pela tela, conferir a ajuda, escolher no composer e receber texto sem nome e com nome em receptor HTTP real no transporte do rig. Sintaxe inválida permanece no campo e não é enviada pelo caso. O receptor substitui o serviço externo; não mede entrega num aparelho. |
| `campanha-com-modelo-aprovado.spec.ts` | Criar campanha de texto pela tela, conferir a ajuda e preparar dois destinatários. Snapshot real congela reserva e nome preenchido. Não inicia campanha nem mede entrega externa. |
| `qa-l12-funil.spec.ts` | Mesmo campo cru no handler de turno e na chamada direta da ferramenta; Postgres real, sequências 0/1/1/2, frase genérica ausente no card, ação concreta preservada e limpeza por `null`. |

O último caso usa o `createFakeRegistry` já existente para o transporte do LLM e
um canal de captura, explicitamente sintéticos. O motor roda em um filho Node
com o `tsx` instalado, separado do loader do Playwright; a conexão com o mesmo
Postgres local é validada antes de executar. Import isolado não prova esse
turno nem a tela: a nova execução do CI continua necessária. Prepara somente seu próprio job
como adquirido; não executa um claim global sobre trabalhos de outras specs.
Não é avaliação de qualidade de um modelo real, nem atendimento completo num
WhatsApp. O handler, a ferramenta, a persistência e a leitura do card são reais.

Automação de WhatsApp/e-mail e follow-up consomem o mesmo `renderTemplate`.
Os testes dos renderizadores e da ação de e-mail medem valor presente, ausente,
escape e sintaxe inválida; o transporte de e-mail nesse teste é dublê. Não há
nova alegação de UX ou entrega SMTP desses caminhos. A ampliação privilegia os
renderizadores distintos e seus consumidores, sem repetir a matriz nas cinco
telas que exibem a mesma ajuda.

## Integração e limites

A fonte é `localStorage` no primeiro caso; nos demais, texto escrito pela pessoa
e dados do contato. Saída: filtro da lista, texto da mensagem e proposta do card.
Preferência local não gera auditoria; os envios e decisões humanas mantêm as
trilhas existentes. Portas: Inbox, Respostas rápidas, Campanhas, Automações,
Follow-ups e quadro do funil. O armazenamento falha sem quebrar a visita;
renderizadores não interpretam uma reserva como variável; a frase descartada
devolve orientação ao modelo para o próximo turno. O laço humano de aprovar ou
ignorar a proposta continua em `NextActionSlot` e no ritual do agente.

Mapas: `inbox-filtros-lembrados.architecture.json`, `captacao-por-webhook` e
`crm-vivo`. Não há schema, identidade, dependência, instalação nem configuração
nova. A fixture central do #3530 é herdada integralmente; não recebe edição
própria. Nenhum build, instalação, TSC ou Postgres foi executado no Mac.

ESLint dos 31 arquivos TypeScript do lote tem zero erros e oito avisos. Dois
ficam no `InboxLayout`: restauração síncrona pós-hidratação herdada do #3402 e
`aplicarLarguras` herdado da main. Os seis restantes ficam em trechos da main
sem alteração: edição de campanha, diálogo de resposta rápida e `inbound-turn`.
Não há atraso artificial, store novo ou supressão para esconder os avisos.

## Reparo da primeira execução

O caso de filtros mantém três canais próprios por organização. Excluir o
escolhido ainda deixa dois, preservando o controle para conferir a limpeza e a
recarga. As asserções de A/B/A, número removido e armazenamento bloqueado seguem.
Os casos de reserva usam a organização única do admin sem exigir um seletor que
não deve existir; o recibo da resposta rápida confere o organization_id, e canal,
público e snapshot da campanha continuam medidos no escopo esperado.

A falha de import foi reproduzida por um worker Playwright real, sem serviços.
Uma prova leve confirmou que o mesmo worker carrega o grafo do motor por um
filho Node + tsx instalado, com rede proibida. Isso prova a ponte de execução;
não prova PostgREST, persistência, envio ou UX. Nenhuma expectativa dos quatro
casos foi removida, nenhum timeout foi ampliado e nenhum teste foi pulado.
