ModularCRM
Em que ordem construir e como verificar
Roadmap de Implementação, ModularCRM
Documento companheiro do DRS, ModularCRM. Responde: em que ordem construir e como verificar cada entrega.
Progresso em três seções (40/40/20). Planejamento 40% (a Fase 0, concluída na aprovação do DRS), Construção 40% (as fases de construção), Testes 20% (o Plano de Testes). Leitura importante do percentual (2026-07-10). O produto V1 (Fases 1 a 5) está essencialmente entregue e em produção com o tenant piloto. A partir de 2026-07-10 o roadmap ganhou a Fase 6, o backlog de paridade com o GoHighLevel, que passou a contar como Construção. Esse backlog foi recortado no mesmo dia ao escopo real do produto (painel interno da Modulareasy, isolamento por subconta, sem revenda white-label): saíram Telefonia, Ecossistema de desenvolvedores e marketplace, Cursos e comunidades, Sites institucionais, Funis e Loja, e a parte de revenda do modo Agência, restando 12 áreas. A Inteligência Artificial foi mantida e recortada (bot de conversa, conteúdo e ações em automação, com custo traga-sua-própria-chave) e a Reputação foi mantida. Por isso a barra de Construção agora mede a jornada até a paridade com o GoHighLevel, e fica baixa de propósito: não significa que o V1 regrediu, significa que o horizonte de evolução ficou maior. As Fases 1 a 5 seguem o estado real do V1; a Fase 6 é direção de produto sem data.
Auditoria de reconciliação (2026-07-10). Foi feito um walkthrough tela a tela do sistema em produção, papel por papel, cruzando cada tela com o banco de dados. O resultado confirmou que a superfície do produto está quase toda construída e que a maior parte dos fluxos internos funciona de ponta a ponta; os problemas se concentram na camada que liga o CRM ao mundo externo (canais, integrações, páginas públicas) e em pontos onde a interface indica sucesso sem que a ação tenha de fato acontecido. Os achados novos entraram como a Onda AUD ao final deste roadmap, e o Plano de Testes recebeu o estado real de cada validação. As notas "ver {AUD-nn}" nos cards abaixo apontam para o achado correspondente. Execução da Onda AUD (atualizado 2026-07-17): a fila começou pelo {AUD-14} (tokens Meta cifrados em repouso, com a fatia F10 regularizada no mesmo merge) e seguiu com o {AUD-01}, entregue e validado em produção em 2026-07-11: o Super Admin em modo "entrar como empresa" passou a enxergar os dados reais da empresa escolhida, com cada entrada e saída registrada no log de auditoria. No mesmo dia o {AUD-02} também foi entregue: o envio de mensagem passou a ser honesto, sem canal conectado o sistema bloqueia com aviso claro e não grava nada; com canal, o status gravado é o resultado real do despacho, e o envio de e-mail deixou de gravar registro duplicado. O alcance daquela entrega era o envio do operador pela tela, que era todo o alcance do RF-CONV-054 na época, e nele ela continua valendo; o levantamento de 2026-07-16 mostrou que o produto despacha whatsapp por outros pontos, que rodam sem pessoa diante da tela e não conferem o canal, e o {AUD-88} emendou o requisito para alcançar todos eles, deixando a entrega do conjunto com o {AUD-83}, entregue em 2026-07-17 junto com o {AUD-84} e o {AUD-90} (merge aca9db6), quando o whatsapp ganhou um lugar único que sonda o estado real do canal e os quatro pontos passaram a decidir por ele; a reconciliação dessa entrega abriu o {AUD-96} (o canal alternativo inutilizável nas duas pontas), o {AUD-97} (a resposta automática de IA desligada em silêncio por falta de chave) e o {AUD-98} (a telemetria de estado do canal que congela por falta de reconciliação). Ainda em 2026-07-11 o {AUD-07} foi entregue: o vínculo entre empresa e plano passou a ser íntegro por gatilho no banco, o tenant piloto Hiit Fitwear ficou no plano Pro real com ciclo de cobrança ativo e limites reais, o MRR do painel passou a ler o preço real do plano, e o cron diário de faturamento, que nunca tinha gerado uma fatura porque respondia 401 desde 2026-04-19, foi destravado e provado gerando fatura de teste. Fechando o dia, o {AUD-03} também foi entregue: a página pública de agendamento voltou a funcionar de ponta a ponta, com as consultas públicas movidas do navegador para o backend (lista fechada de campos, sem afrouxar o isolamento), horários no fuso do calendário, gravação honesta que recusa horário ocupado e cancelamento por link, tudo provado em produção com um agendamento real criado, vinculado a contato e cancelado. Também em 2026-07-11 o {AUD-04} foi entregue: o chat público e o widget de webchat voltaram a funcionar, corrigindo cinco defeitos combinados (endpoint chamado sem o prefixo da API, coluna do visitante ausente na tabela de contatos, coluna errada na listagem de mensagens, resposta de pré-voo CORS faltando no widget e status de entrega que nunca fechava), com o widget testado embedado num site externo e a conversa completa provada ponta a ponta em produção. Ainda em 2026-07-11 o {AUD-05} foi entregue: a aba SaaS do painel da agência voltou a abrir sem quebrar (a consulta de uso por organização passou a informar o nome do plano e a tela ficou resiliente a organização sem plano, mostrando "Sem plano" em vez de derrubar o painel), a participação de MRR passou a ser exibida como percentual real (antes mostrava o valor absoluto como se fosse porcentagem) e o gráfico de distribuição ficou legível no celular; a decisão de escopo foi manter a tela, que corresponde ao painel consolidado de status e uso por subconta previsto no DRS. Ainda em 2026-07-11 o {AUD-06} foi entregue: a tela de "Templates de Workflow" da agência voltou a funcionar de ponta a ponta, corrigindo quatro defeitos combinados (resposta embrulhada da API tratada como lista, consulta com filtros caindo em rota inexistente, criação que ignorava o estado inativo e lista fixa de categorias que corrompia categorias reais ao editar), com a listagem de rascunhos inativos restrita ao super admin e a validação provada em produção com lista, estado vazio, duplicação e filtros. {AUD-09} foi entregue: o botão de criar oportunidade da ficha do contato deixou de cair em página inexistente e passou a abrir o funil com a janela de nova oportunidade já vinculada ao contato (nome pré-preenchido e vínculo gravado ao salvar), com o atalho de agendar do mesmo menu corrigido no mesmo merge; a exclusão de contato que falha em silêncio descoberta no teste virou o card {AUD-18} e o reforço de isolamento no vínculo contato-oportunidade virou o {AUD-19}. {AUD-18} foi entregue fora de ordem por pedido direto: a exclusão de contato deixou de fingir sucesso; o banco ganhou regras de remoção e anonimização dos vínculos (com respaldo de LGPD nos formulários), qualquer falha real vira aviso claro mantendo o operador na ficha, e a confirmação diz o que sai junto. {AUD-08} foi entregue: os rótulos da ficha do contato voltaram a exibir acentuação correta (a corrupção estava em quinze linhas do código do componente, único ponto do app, recodificadas de forma cirúrgica e provadas sem resíduo em produção). Em 2026-07-12 o {AUD-10} foi entregue (merge b48fc8b): um gatilho genérico de auditoria passou a gravar criar, editar e excluir de operador em 22 tabelas de gestão, com autor, tipo, entidade, rótulo e data (escritas de sistema ficam fora, salvar sem mudar nada não grava, e falha de auditoria nunca derruba a ação do usuário); a tela de Registro de Auditoria passou a ler essa trilha real em vez da tabela errada que lia antes; e dois defeitos históricos na função de mesclagem de contatos (insert em colunas inexistentes e sintaxe inválida na verificação de organização) foram corrigidos no mesmo merge, com a mesclagem voltando a funcionar e a gravar a ação na trilha. O QA dessa entrega encontrou dois achados de polimento pré-existentes e não bloqueantes, que viraram os cards {AUD-20} (tema claro e mobile quebrados em Configurações) e {AUD-21} (403 nas sugestões de mesclagem da ficha do contato). {AUD-11} foi entregue em 2026-07-12 (merge df025d9): as janelas de nova tarefa, nova oportunidade e novo produto passaram a fechar ao salvar com sucesso, com o item aparecendo uma única vez na lista, e deixaram de fingir em caso de erro: quando o salvamento falha, a janela permanece aberta com os dados preservados e um aviso claro (sem expor mensagem técnica) no lugar de travar em silêncio, e o envio acidental em duplicidade é bloqueado. Em 2026-07-12 o {AUD-20} foi entregue (merge e991e03): a sub-navegação de Configurações passou a seguir o tema claro e o escuro pelos tokens do sistema e, em telas estreitas, virou um seletor no topo com o conteúdo em largura total, sem espremer. Em 2026-07-12 o {AUD-21} teve o defeito de 403 corrigido (merge a681a9a): as chamadas de leitura da ficha do contato (sugestões de mesclagem, identificadores e configuração de correspondência) passaram a reconhecer o Super Admin da operação, que antes recebia 403 ao abrir a ficha de um contato de uma empresa da qual não é membro; o isolamento foi preservado, quem não é membro nem Super Admin continua bloqueado. O card, porém, segue em aberto (parcial) porque a segunda metade do aceite não é atingível hoje: a sugestão automática de duplicados por identificador nunca produz candidato sob a regra de unicidade (empresa, tipo, valor) da tabela de identificadores, que impede dois contatos da mesma empresa dividirem o mesmo identificador. Esse defeito estrutural do casamento de duplicados foi catalogado como {AUD-22}. {AUD-13} foi entregue em 2026-07-12: as empresas de teste e internas ficaram ocultas por padrão na listagem de Subcontas (só o tenant real Hiit aparece), com selo Teste, um toggle para revelá-las e uma ação de linha que marca ou desmarca de forma reversível, sem apagar nada e sem afetar o entrar-como-empresa, validado por smoke visual real (claro, escuro e mobile) e QA E2E. {AUD-15} foi entregue em 2026-07-12 (merge a3d2158): o servidor de integrações passou a reconhecer o Super Admin em modo entrar-como-empresa nas ações que dependem do servidor (envio de e-mail e mensagens/comentários no Meta), com o mesmo reconhecimento transversal já usado na leitura e sem afrouxar o isolamento do usuário comum, provado em produção. Durante essa entrega o code review encontrou três endpoints de servidor sem verificação de autenticação (envio de campanha, envio de SMS e convite de membro), catalogados como {AUD-26} por serem risco de segurança independente do {AUD-15}. O {AUD-26} foi entregue em 2026-07-12 (merge e7cf713): os três endpoints de servidor sem autenticação (envio de campanha, envio de SMS e convite de membro) passaram a exigir token e acesso à empresa (membro ou Super Admin), o convite passou a derivar o autor do token e o front a enviá-lo, e o envio de campanha (que estava com a rota morta pelo reescrita do Nginx) voltou a funcionar autenticado. Durante essa entrega foi catalogado o {AUD-27} (outros handlers registrados só com o prefixo /api/ ficam mortos pelo mesmo reescrita do Nginx, alguns com tela quebrada como salvar configuração de e-mail e de SMS). O {AUD-16} foi entregue em 2026-07-12 (merge 9a4be41): endurecimento do agendamento público, com validação da janela de disponibilidade na gravação, garantia atômica no banco contra dois agendamentos no mesmo horário, limite por IP nas leituras públicas e cancelamento por código com validade. O {AUD-17} foi entregue em 2026-07-13 (merge b5df2a8): endurecimento do chat público, mesma classe do {AUD-16} mas para o chat, com a leitura do histórico de uma conversa passando a exigir prova de posse pelo identificador do visitante (antes bastava saber o id da conversa), rate-limit por IP no envio de mensagens e validação de tamanho e formato dos campos. O {AUD-19} foi entregue em 2026-07-13 (merge 807424e, migration 085): o vínculo entre contato e oportunidade passou a ser validado por gatilho no banco, que recusa contato de outra organização independentemente de quem chama; a permissão de criar oportunidade no frontend deixou de liberar por padrão enquanto o papel do usuário carrega ou falha, e a falha na consulta de funis passou a mostrar erro claro com opção de tentar novamente em vez de sumir em silêncio. O code review dessa entrega achou um ponto estrutural fora do escopo da fatia, catalogado como {AUD-29}: as permissões de papel hoje só valem no frontend, sem reforço equivalente no banco. Em 2026-07-13 a Onda AUD avançou: o {AUD-22} foi entregue (merge d12c179, migration 086), com a detecção de duplicados passando a comparar e-mail e telefone normalizados, o que destravou de vez o {AUD-21}, fechado no mesmo movimento porque o Super Admin passou a ver a sugestão real de duplicados e a concluir a mesclagem de fato. O teste de não regressão dessa entrega encontrou a mesclagem quebrada (500) para todo mundo havia cerca de dois meses, corrigida no mesmo merge como {AUD-30}, e essa correção revelou duas pendências novas: {AUD-31} (rotas de trigger links quebradas por variáveis indefinidas) e {AUD-32} (o modo entrar como empresa não alcança o restante do canal /api do webhook). Em 2026-07-13 o {AUD-23} foi entregue: os rótulos em inglês que restavam fora de Configurações (os cabeçalhos da tabela "Relatório por Origem" no painel inicial e os textos da tela de Pontuação Global no portal da agência) foram traduzidos para português, validados em produção nos modos claro, escuro e mobile. Em 2026-07-13 o {AUD-24} foi entregue: o seletor de Tipo de Empresa (Perfil da Empresa) passou a listar os tipos jurídicos brasileiros (MEI, EI, EIRELI, SLU, Ltda., S.A., Sociedade Simples, Sem fins lucrativos, Outro), e os cadastros existentes foram migrados sem perda de dado. Em 2026-07-14 o {AUD-25} foi entregue: as empresas de teste deixaram de ser contadas e listadas por padrão nas telas do Super Admin (indicadores de organizações e MRR do painel da agência, seletores de organização em Criar e Aplicar Snapshot, tabela de Whitelabel e o seletor "Sub-conta" do cabeçalho), com a opção de revelá-las por um interruptor onde faz sentido; o QA da fatia abriu o novo {AUD-33} (os indicadores de Usuários e Contatos do painel ainda contam empresas de teste). Em 2026-07-14 dois itens da fila foram entregues. O {AUD-27} foi entregue (merge 2146cfb): as dez rotas do servidor de integrações que a reescrita do Nginx deixava mortas (Google Calendar, reprocessar nomes de contatos do Meta, salvar configuração de e-mail e de SMS, relatórios de Google Analytics, Meta Ads e Google Meu Negócio, e formulários do Meta Leads) voltaram a responder pela URL pública com o mesmo guardião de autenticação do {AUD-26}, e as duas rotas que gravam credencial (senha SMTP, token do Twilio) passaram a exigir dono ou administrador da empresa. No qa dessa entrega apareceu, em handler distinto, o {AUD-34} (também entregue em 2026-07-14): a criação de conta de e-mail em Caixas de Email não funcionava por faltar o identificador da empresa no envio, e o interruptor de pular teste de conexão do Super Admin não era honrado pelo botão Salvar; os dois defeitos foram corrigidos e provados em produção. Dito sem maquiagem: a listagem de Caixas de Email ainda fica cega quando o Super Admin usa o modo entrar como empresa, isso está rastreado no {AUD-32} e não foi tocado nesta entrega. Planejamento do {AUD-29} (2026-07-14): quatro achados que mudaram a fila, registrados antes de escrever qualquer código. Primeiro, um problema de segurança grave e independente do card: as tabelas de formulários e de campanhas têm as regras de isolamento escritas mas com a proteção desligada, e ficou provado em produção que qualquer pessoa, sem login, de posse apenas da credencial pública que acompanha o site, lê o formulário cadastrado e a empresa dona dele, podendo ainda inserir, alterar e apagar. Virou o {AUD-35} e passou à frente do {AUD-29} na fila, porque é um rombo vivo enquanto o {AUD-29} corrige um risco ainda dormente. Por consequência, o teste {A-061} do Plano de Testes, que declarava o isolamento firme desde 2026-07-10, foi reaberto: ele estava aprovado e mentindo. Segundo, o modelo de papéis granulares (RF-PERM-001, Essencial) não está implementado: existem a tabela, o vínculo do membro com o papel e o controle que esconde botões, mas não existe tela nenhuma para o administrador criar ou atribuir papel, e em produção não há um único papel cadastrado nem um membro que não seja dono. Virou o {AUD-37}, e significa que o {AUD-29} endurece a metade-banco de uma funcionalidade cuja metade-produto ainda não existe: é defesa em profundidade legítima e barata, mas não entrega o RF-PERM-001, e este roadmap não vai dizer que entrega. Terceiro, o aceite do {AUD-29} falava em "uma ação" sem dizer quais, e requisito vago não reprova nada: foi escopado às ações de escrita, que é o que o próprio sintoma do card descreve, e ver e exportar saíram para o {AUD-36}, porque reforçá-los pela mesma técnica derrubaria o agendamento público e faria consultas voltarem vazias em silêncio. Quarto, várias telas consultam o controle de permissão por módulos que não existem no catálogo ou pelo módulo de outra entidade, o que hoje é inofensivo e vira defeito no primeiro papel restritivo: virou o {AUD-38}. O {AUD-35} foi entregue em 2026-07-14 (merge 51a055a), no mesmo dia em que foi descoberto. A proteção de isolamento foi ligada nas duas tabelas e em mais três da mesma família (cliques e aberturas de campanha e passos agendados de automação, que estavam sem proteção e sem nenhuma regra, e alcançam a empresa por vínculo), e as três ganharam regra de leitura pela empresa dona. Nenhuma das regras que já existiam foi alterada, e nenhuma regra de leitura pública foi criada: ficou provado por leitura de código e por requisição real que a página pública de formulário não lê a tabela direto, ela passa pelo servidor de integrações, que tem acesso próprio e não depende dessa proteção. Provas: quem não fez login passou a receber lista vazia em formulários e campanhas (antes recebia o formulário e a empresa dona), a tentativa de alterar o endereço de redirecionamento do formulário sem login não altera mais nada, e a página pública de formulário continua respondendo e recebendo envio. A migração ainda instalou um verificador que aborta qualquer migração futura se alguma tabela com dono de empresa ficar sem proteção, para esta classe de defeito não voltar. Causa-raiz, dita sem maquiagem: as duas tabelas nasceram antes do controle de migrações, com as regras certas escritas e sem o comando que as liga, e a auditoria de proteção feita em 2026-05-12 corrigiu a tabela filha (as respostas dos formulários) mas foi escopada a uma lista de catorze tabelas e nunca olhou a tabela mãe, deixando o furo aberto por cerca de dois meses. A lição virou regra: auditoria de isolamento se faz por critério (toda tabela que tem dono de empresa), nunca por lista curada. Durante essa entrega apareceu o {AUD-39}: a regra de leitura pública dos calendários libera todo calendário ativo sem filtrar empresa, e a evidência aponta que ela virou código morto depois que o {AUD-03} moveu as consultas públicas para o servidor. Por causa dele o teste {A-061} segue reprovado. O {AUD-29} foi entregue em 2026-07-14 (merge b74e049, migration 089). As permissões de papel, que até aqui só existiam no navegador, passaram a valer também no banco para as ações de escrita: uma função de autorização espelha regra por regra o mesmo controle que o frontend usa para esconder botões, e regras de escrita em nove tabelas de gestão consultam essa função antes de deixar criar, editar ou excluir. Nenhuma regra de isolamento por empresa que já existia foi alterada, e o reforço só nega, nunca concede. A prova foi feita por requisição real com o token de um membro de verdade, não por leitura de código: com o papel negando criar, a gravação é recusada e nada entra; com o papel permitindo, a mesma requisição passa; dono, administrador e Super Admin não sentiram diferença, inclusive no modo entrar como empresa; e o agendamento e o formulário públicos continuam funcionando, porque passam pelo servidor de integrações, que tem acesso próprio. O code review pegou, e a correção entrou antes do merge, uma divergência que teria deixado o banco mais frouxo que a tela: a checagem da permissão aceitava textos como "yes" no lugar de sim/não e chegava a quebrar com erro diante de um valor inesperado, em vez de simplesmente negar. Dito sem maquiagem, e repetindo o que o próprio card avisa: isto não entrega o RF-PERM-001. Continua não existindo tela para criar ou atribuir papel, e em produção seguem zero papéis cadastrados e nenhum membro que não seja dono, então o que este card fecha é um risco real mas dormente, esperando o {AUD-37}. Duas ressalvas honestas ficam registradas: uma escrita recusada em editar ou excluir volta silenciosa, como "nada a fazer", em vez de erro (o dado fica protegido, mas quem ligar a tela de papéis não pode ler esse silêncio como sucesso), e o reforço só alcança os módulos que existem no catálogo do produto, deixando formulários, produtos e tarefas sem regra de papel. Durante a validação apareceu o {AUD-41}: criar um usuário provisiona uma empresa automaticamente, e excluir o usuário deixa essa empresa órfã contando como cliente real no painel do Super Admin. Sessão de 2026-07-15 ({AUD-31}). A correção dos links rastreáveis foi feita e está no ar: os três endereços (criar, listar e apagar) liam duas variáveis de configuração que nunca existiram no arquivo, então estouravam antes de qualquer lógica e devolviam erro em toda chamada autenticada. Não é regressão: nasceram assim e nunca funcionaram em produção desde que foram escritos. A correção são três nomes de variável, e o aceite foi provado por requisição real (caso positivo e negativo) e também pela tela, por clique real de mouse: criar, listar, abrir o link curto, ver o contador subir e apagar, nos temas claro e escuro. O card foi fechado. Nesta sessão também foi decidido, com razão técnica registrada no {AUD-32}, não encaminhar ali a marca de entrar como empresa: a função que cria o link resolve a empresa por conta própria e ignoraria a marca, enquanto listar e apagar a honram, de modo que o Super Admin criaria um link que sumiria da própria lista. O achado maior da sessão não estava no card: ao conferir o que o DRS promete para links rastreáveis, descobriu-se que o editor de automações oferece gatilhos que a tela aceita e o produto nunca dispara: a automação fica salva como ativa e nunca roda. Virou o {AUD-43}, e o DRS, que afirmava que esses gatilhos "já existem", foi corrigido e republicado no mesmo dia. Reconciliação de 2026-07-15: a contagem da primeira versão do card estava errada e foi refeita conferindo emissor por emissor no código. O número certo é vinte gatilhos oferecidos, onze com emissor real, oito sem emissor nenhum e um (execução manual) que por desenho só roda quando outra automação o aciona. Errou porque contou por busca de texto literal, e cinco emissores escapam dela: as tags saem de um condicional e o ganho ou perda de oportunidade sai de um nome montado em tempo de execução. O risco é real mas dormente: as três automações em produção usam o gatilho de novo contato, que funciona, e a empresa cliente não tem automação nenhuma. Ainda da sessão de 2026-07-15, três achados menores foram catalogados e não corrigidos, para não inchar a fatia: o {AUD-44} (apagar link rastreável de outra empresa responde sucesso sem apagar nada. Entregue 2026-07-24 (merge ea19db9): o handler de exclusão passou a usar .select() e a checar linhas afetadas; zero linhas (RLS, outra empresa ou inexistente) responde não-encontrado (404), nunca sucesso falso. Provado com token real do c3po em produção (DELETE de link inexistente devolve 404 not_found) e por qa com RLS real (o dono apaga e recebe 200, o não-dono recebe 404), com a Hiit intacta., dormente porque o isolamento protege e só é alcançável por chamada direta), o {AUD-45} (o ajuste de tamanho do endereço curto existe no painel e não faz nada) e o {AUD-46} (uma leitura de contato devolveu erro durante navegação normal, ainda não investigada). O {AUD-47} foi entregue em 2026-07-15 (merge 67b7051), no mesmo dia em que nasceu. O barramento de eventos, que é o endereço por onde a tela avisa o servidor que um fato aconteceu, estava alcançável pela internet aberta e aceitava disparo sem autenticação nenhuma: bastava saber o identificador de uma empresa para fazer as automações ativas dela rodarem contra um contato escolhido, e as ações de automação enviam mensagem de verdade. Agora exige sessão válida e vínculo com a empresa alvo, reaproveitando a mesma verificação que a rota vizinha de convite já usava desde o {AUD-26}. O racional foi corrigido durante a investigação: o identificador da empresa não é público (o widget do site do cliente usa o apelido, não o identificador), mas ele é identificador e não credencial, nunca muda e é conhecido por qualquer um que um dia teve acesso, então, sem checagem de usuário, excluir alguém não revogava nada. Provas por requisição real: sem token responde recusa e nada dispara (antes respondia sucesso e criava duas execuções), token inválido idem, e o caminho legítimo continua funcionando, provado por clique real de mouse na tela, com as execuções subindo de treze para quinze e o registro gravado no banco, inclusive no modo entrar como empresa. Ressalva honesta registrada: a recusa por falta de vínculo não foi exercitada, porque os usuários disponíveis são super administradores e a verificação aprova por esse caminho antes de olhar o vínculo. Foi este card que expôs que o {AUD-43} estava apoiado em duas premissas falsas, hoje corrigidas no próprio card. O {AUD-43} foi entregue em 2026-07-15 (merge c6a0dbb), no mesmo dia em que o {AUD-47} nasceu dele. A lista de gatilhos do editor de automações passou a dizer a verdade: eram vinte gatilhos oferecidos, oito deles sem ninguém que os disparasse, e agora são treze, todos com emissor real, exatamente os treze que o RF-AUTO-002 nomeava naquela hora (na tarde do mesmo dia o requisito passou a nomear quinze, pela reentrada decidida de dois gatilhos; ver {AUD-52} e {AUD-53}). A causa-raiz foi corrigida antes da lista: a mesma lista existia quatro vezes no código e já tinha divergido (nove dos vinte sem rótulo, por isso o gatilho de formulário enviado, que funciona, aparecia como texto técnico cru na tela), e havia até um comentário prometendo uma sincronia que nada garantia; agora existe uma fonte única e as demais derivam dela. Sete gatilhos saíram da lista por decisão registrada no requisito, o rótulo da execução manual parou de prometer um botão que a tela não tem, e o template que entregava automação quebrada em um clique foi removido. O gatilho de agendamento marcado, único dos oito que o requisito nomeia, ganhou emissor nos dois caminhos por onde o agendamento nasce. Provas: pela tela, o editor mostra treze gatilhos e nenhum outro (conferido no valor do campo, não no rótulo); uma automação antiga com gatilho removido abre, mostra rótulo legível e continua com o gatilho intacto depois de salvar; e o agendamento passou a disparar a automação pelos dois caminhos, provado por execução gravada no banco, com o par negativo (automação desligada não gera execução). Uma ressalva honesta: o modo escuro do construtor é parcial e o aparelho móvel não foi verificado, ambos pré-existentes e não introduzidos por esta entrega. Pendentes acionáveis da fila agora (atualizado 2026-07-15): {AUD-57} (o agendamento público cria contato sem disparar automação, entregue o {AUD-49} em 2026-07-15, é agora o próximo item acionável da fila, e é um dos três caminhos com tráfego real que ainda estão mudos, ver {AUD-66}), {AUD-58} (o gatilho de mensagem recebida ignora quatro canais), {AUD-48} (enumerar por script toda rota exposta pela reescrita do servidor de borda), {AUD-50} (a coleta de e-mail recusa o próprio agendador), {AUD-59} (o aviso de limite de armazenamento só dispara para quem manda e-mail), {AUD-60} (ação em massa no funil não dispara o que a ação individual dispara), {AUD-32} (entrar como empresa no canal /api, com a instância nova do {AUD-34} documentada no próprio card), {AUD-33} (indicadores de Usuários e Contatos do painel da agência ainda contam empresas de teste), {AUD-39} (regra de leitura pública dos calendários cega quanto à empresa), {AUD-41} (empresa órfã ao criar e excluir usuário), {AUD-37} (a tela de Papéis e Permissões, que é o que de fato entrega o RF-PERM-001), {AUD-36} (reforço de ver e exportar) e {AUD-38} (chaves de módulo divergentes), {AUD-44}, {AUD-45} e {AUD-46} (os três achados menores de 2026-07-15). Adiados por decisão, com o motivo registrado no próprio card: {AUD-54} (status da conversa alterado tem cinco pontos de escrita e risco de laço) e {AUD-55} (fatura paga e fatura vencida dependem da cobrança automática da V2). Decididos em 2026-07-15 e promovidos de pendência a trabalho especificado, aguardando a vez na fila: {AUD-52} (o lembrete de agendamento vira automação montável e o agendador para de mandar sozinho), {AUD-53} (contato atualizado volta, com filtro por campo obrigatório) e {AUD-56} (o botão de executar automação na mão, com requisito próprio no RF-AUTO-043). O documento está à frente do código de propósito, e isto não é drift (2026-07-15). O RF-AUTO-002 nomeia dezesseis gatilhos e a tela oferece catorze. A ordem dos fatos explica a diferença: de manhã o {AUD-43} (merge c6a0dbb) subiu a lista honesta de treze, tirando os sete que não tinham emissor; à tarde o Wladimir decidiu a reentrada de dois deles, o lembrete de agendamento e o contato atualizado, subindo o requisito de treze para quinze nomeados, e o requisito foi emendado antes de qualquer código, como manda a regra; ainda na mesma tarde o RF-CONV-014 foi reconciliado e ganhou o décimo sexto gatilho nomeado, o clique em link rastreável, que o {AUD-51} entregou no mesmo dia, merge 109857f, subindo a tela de treze para catorze. Portanto os dois gatilhos que faltam na tela são backlog especificado ({AUD-52} e {AUD-53}), não defeito e não promessa esquecida. Quem for reconciliar documento e código nesta área: a correção é construir os dois gatilhos, nunca apagá-los do RF-AUTO-002. O DRS é lei e o código corre atrás dele, nunca o contrário. O {AUD-40} foi entregue em 2026-07-14 (merge b9a9e37), no mesmo dia em que nasceu: a saída do modo entrar como empresa limpava só parte do estado e deixava a empresa ativa gravada no navegador, então o modo voltava sozinho na navegação direta por endereço. A correção reaproveitou uma função de limpeza que já existia no código e que já prometia, na própria documentação dela, ser usada nessa saída, mas não era. Além do estado guardado, a empresa em memória também passou a ser zerada: mantê-la fazia a empresa visitada continuar sendo o escopo das telas depois da saída e realimentava a entrada seguinte, que era o que gerava o defeito. O teste provou os dois lados: não volta mais sozinho, e quem sai volta para a própria empresa em vez de ficar sem nenhuma. O {AUD-28} (ponte de trigger links do WhatsApp Evolution) segue parkeado, dependente do QR code do WhatsApp para prosseguir. Sessão de 2026-07-15 (segunda parte), o barramento de eventos. Ao planejar o conserto dos gatilhos apareceu um furo de segurança vivo: o endereço que recebe os eventos do sistema aceita disparo de qualquer pessoa da internet, sem login nenhum, e executa as automações ativas da empresa indicada, enviando mensagem de verdade ao contato e consumindo cota. Virou o {AUD-47}, P0, entregue e mergeado em 2026-07-15, no mesmo dia em que nasceu (o relato completo da entrega está acima). O DRS não cobria o caso: o requisito de isolamento falava em não retornar dados de outra empresa, ou seja, tratava de leitura, e o furo é de ação. Requisito vago não reprova nada, então o DRS foi emendado antes de qualquer código: o isolamento passou a valer também para escrita e nasceu o RNF-010 (Perímetro autenticado), que exige sessão válida e vínculo com a empresa alvo em todo endereço de servidor alcançável pela internet, antes de qualquer efeito. Do mesmo trabalho saíram mais três cards: o {AUD-48} (a auditoria dessa classe foi feita por lista curada e deixou passar justamente este endereço, então a varredura tem que ser exaustiva e por script), o {AUD-49} (o webhook público de captura de lead chama o motor de eventos com o nome de campo errado, então o contato entra e a automação nunca roda) e o {AUD-50} (a coleta de e-mail recusa o próprio agendador, porque ele manda o segredo no cabeçalho e essa rota, sozinha entre as irmãs, só lê o segredo no endereço).
Sessão de 2026-07-15 (terceira parte), o planejamento do {AUD-43} e o que ele revelou. Antes de escrever uma linha de código para consertar a lista de gatilhos, o planejamento conferiu emissor por emissor e achou a causa-raiz que o card não via: a lista de gatilhos existe quatro vezes no código, mantida à mão, e as quatro já divergiram entre si. Por isso a correção não é editar as listas, o que reintroduziria o drift no card seguinte, e sim fazer as telas derivarem de uma fonte só. O planejamento também achou uma armadilha ativa que desmente o "risco dormente" do card: um dos modelos prontos de automação entrega, em um clique, uma automação com um gatilho que nunca dispara, e dois dos três workflows que existem em produção nasceram de modelos. Como manda a regra, o documento foi emendado antes do código. O RF-AUTO-002 deixou de listar eventos "como" isto ou aquilo (lista ilustrativa não reprova nada, e foi ela que deixou os oito gatilhos mortos conviverem com o requisito sem violá-lo) e passou a nomear o conjunto exato dos treze gatilhos que o produto oferece, com a regra de honestidade explícita (a lista da tela não pode oferecer gatilho que o produto não dispara, e nenhum gatilho vale só para parte dos caminhos) e com os sete que saem declarados fora do escopo atual, para que sair da lista não vire drift no futuro. O RF-CONV-014 foi reconciliado na direção inversa, que é a mais perigosa: ele afirmava como fato existente que o clique em link serve de gatilho, e isso era falso nos dois sentidos (o gatilho não existe em lugar nenhum, e o clique é gravado sem contato atribuído, então não haveria a quem inscrever). Virou o {AUD-51}. Do mesmo planejamento saíram mais nove cards: {AUD-52} a {AUD-56} (os gatilhos adiados e o botão de executar, cada um com o motivo registrado), {AUD-57} (o agendamento público cria contato sem disparar automação, irmão do {AUD-49}), {AUD-58} (o gatilho de mensagem recebida ignora SMS, chat do site, Instagram e Messenger), {AUD-59} (o aviso de limite de armazenamento só dispara para quem manda e-mail) e {AUD-60} (mover oportunidades em massa não dispara o que mover uma dispara). Os quatro últimos são da mesma família do {AUD-49} e merecem prioridade explícita, porque são mais graves do que a contagem de gatilhos do {AUD-43} sugere: não são gatilhos que faltam, são gatilhos que existem, estão na lista, e mentem em parte dos caminhos. Esse é o defeito mais difícil de perceber, porque o teste feito por um caminho passa.
O {AUD-51} foi entregue em 2026-07-15 (merge 109857f), no mesmo dia em que nasceu, com o front buildado, o webhook reiniciado e a rota pública respondendo 200 em produção. O clique em link rastreável virou gatilho de automação de verdade, com o contato atribuído. A URL do link curto virou /l/<slug>?c=<token>, com um id opaco de envio de 32 hex por par de link e contato, emitido pela RPC issue_link_token, que exige que o link e o contato sejam da mesma empresa; o identificador do contato não viaja na URL, porque identificador não vale como credencial (RNF-010). A função register_click passou a resolver o contato pelo token escopado ao próprio link, grava o clique com o contato atribuído e lança a linha no histórico dele, aba Atividade, tipo link_click. A rota responde o redirecionamento primeiro e só então emite o evento link.clicked em processo, e só quando há contato atribuído: clique anônimo, token de outro link ou token de outra empresa redirecionam e contam, e não atribuem nem disparam nada. O endereço curto do link passou a ser único em todo o produto, não mais só por empresa, porque o resolvedor não olhava a empresa e isso teria feito o evento nascer para a empresa errada. A merge tag {{link.<slug>}} nas ações de automação passou a expandir para a URL com o token daquele contato, com o endereço base vindo do ajuste shortlink_base_url, editável no painel, sem valor fixo no código. Na tela, o editor de automações passou a oferecer catorze gatilhos, um a mais que antes: entrou Clique em link rastreável, em Mensagens, confirmado na própria tela em produção. De quebra, a aba Atividade passou a exibir rótulo em português para os seis tipos de evento, que antes apareciam com o nome cru em caixa alta (NOTE, TASK). Gates: plan APPROVED, qa PASS, review APPROVED, zero Critical, checagem de antirregressão limpa. Migration 090 aplicada, com backup em /root/backups/mcrm/backup_pre_090_20260715_192803.dump; a prova de volta ao normal conferiu workflow_runs em 13 e trigger_links em 0, com a Hiit intacta, 1503 contatos. Duas ressalvas honestas ficam registradas: o caminho de agendamento com a variável do nome do contato não foi exercitado ao vivo, coberto por revisão de código, linhas não tocadas por esta entrega, e o aparelho móvel não foi verificado; e a variável do nome do contato chegou vazia na atividade disparada pelo clique, que é o defeito pré-existente já catalogado no {AUD-61}, não introduzido por esta entrega.
O {AUD-49} foi entregue em 2026-07-15 (merge 5e4f590), no mesmo dia em que nasceu. O webhook público de captura de lead chamava o motor de eventos com o campo errado e com o pacote de dados na forma errada; o motor recusava em silêncio, o contato nascia e a automação nunca rodava. Corrigido: agora chama certo, e a guarda do motor deixou de ser muda, passando a registrar no log o evento malformado em vez de sumir. Mas o planejamento desta fatia varreu por critério, não por amostra, todos os pontos do produto que criam contato, e achou uma realidade maior do que o card supunha: dezoito pontos criam contato, cinco emitem o evento de novo contato (quatro provados no backend e um, o do frontend, não provado; o número foi corrigido de quatro para cinco em 2026-07-16, e o conjunto passou a fechar) e treze não emitem; não é um quebrado mais um irmão, são um quebrado e treze mudos. O dado que mais incomoda: dos contatos dos últimos trinta dias, seis vieram do livechat, quatro do agendamento público e três do formulário, zero do webhook de captura de lead; os três caminhos com tráfego de verdade seguem mudos, e o {AUD-49} consertou o único caminho sem tráfego. O RF-AUTO-002 continua violado pelos outros caminhos e este card não o entrega. Seis cards novos nasceram desta fatia: {AUD-65} (a raiz, duas portas para o mesmo fato, uma exaustiva por construção via gatilho de banco e outra exaustiva só por disciplina, com recomendação de decidir por council antes de abrir os doze pontos mudos), {AUD-66} (os doze pontos mudos, nominais, priorizando livechat e formulário porque são os dois com tráfego real), {AUD-67} (lead com mensagem derruba o webhook com erro quinhentos, defeito pré-existente achado pelo qa), {AUD-68} (o passo de automação "adicionar tag" marca sucesso sem aplicar a tag, mesma família da Onda AUD), {AUD-69} (a guarda nova pode logar dado pessoal do contato, achado do review) e {AUD-70} (o {AUD-49} referenciava o requisito errado, RF-LEAD em vez de RF-CAPT-004, e o requisito de captura não reprova o silêncio da automação). Recomendação explícita: decidir o {AUD-65} antes de abrir os doze cards do {AUD-66} um a um, porque um conserto na raiz evita pagar doze vezes o mesmo tipo de correção.
Sessão de 2026-07-15 (quarta parte), o qa do {AUD-49} revalidado e duas fatias novas. O qa desta última entrega, testando com lead trazendo o campo de mensagem, achou que o webhook quebrava com erro quinhentos mesmo depois de criar o contato: virou o {AUD-67}, entregue no mesmo dia, merge aaa0c29. A causa era um catch encadeado num resultado da biblioteca de acesso ao banco que só parece uma promessa, mas não é uma de verdade (é thenable, não tem catch), e o TypeError também pulava a chamada seguinte do motor de eventos: lead com mensagem não disparava zero notas e zero execuções, não só erro quinhentos. Provado por controle antes e depois do conserto, e em produção depois: sucesso, nota gravada, evento contact.created, duas execuções, nota visível na tela do contato nos dois temas. Consequência para o {AUD-49}: por cerca de duas horas o marcador de concluído daquele card foi verdade parcial, porque o teste da época só exercitou lead sem mensagem; o qa desta fatia revalidou o {AUD-49} nos dois ramos e hoje o marcador de concluído é verdade de fato, com a nota registrada no próprio card. Na mesma varredura apareceram mais duas ocorrências do mesmo tipo de erro, em pontos que liberam o lock de conversa do Instagram e do Messenger dentro de um finally: o TypeError ali também mascarava a exceção original do try e impedia a mensagem do cliente de entrar no inbox. Viraram o {AUD-71}, P1 latente porque o caminho nunca rodou em produção (a conexão Meta está morta pelo {AUD-42}), entregue na mesma branch e no mesmo merge. O qa do {AUD-71}, medindo depois do conserto, achou que o lock às vezes continua preso por outra causa, arquitetural e pré-existente, lock de sessão combinado com o pool de conexão persistente do PostgREST: virou o {AUD-72}, P1, sem conserto nesta fatia. O mesmo qa mediu o contraste do rótulo da linha do tempo do contato e achou reprovação do RF-UX-004, pré-existente e não introduzida por nenhuma fatia recente: virou o {AUD-73}. Ao fim daquele dia o próximo item acionável da fila era o {AUD-57} (o agendamento público cria contato sem disparar automação), e a sessão seguinte mudou essa ordem: ver o parágrafo de 2026-07-16 abaixo.
Sessão de 2026-07-16, o {AUD-68} replanejado e o requisito que faltava. O planejamento do {AUD-68} varreu por critério, e não por amostra, as vinte e uma rotas de ação do motor de automação, e achou uma realidade maior que a do card: nenhuma delas confere o próprio efeito antes de dizer concluído. O estado do passo não vem da ação, vem da ausência de erro, e nada no motor produz erro, então o registro só sabe dizer uma coisa. O dado que fecha o diagnóstico: em toda a história do produto os passos de automação registraram dezoito vezes concluído, uma vez em execução, e nenhuma vez falha ou ignorado. Um campo de estado que só assume um valor não é estado, é enfeite. A emenda veio antes do código, e era obrigatória: nenhum requisito reprovava isto. O RF-CONV-054 trata da mensagem e o gatilho do H1 dele é o operador tentando enviar pela tela, então a condição dele nunca ocorre aqui, onde quem roda é o motor sozinho e metade dos casos não é mensagem nenhuma. Nasceu o RF-AUTO-044, publicado no DRS em 2026-07-16, que define os três desfechos do passo (concluído, ignorado, falha), o discriminador entre eles (a ausência é do dado ou da empresa, e então ignora e segue; ou é da configuração, e então falha e para), a divergência deliberada de que empresa sem canal conectado gera ignorado e não falha, e a regra de honestidade da lista de ações, espelhando a que o RF-AUTO-002 recebeu em 2026-07-15 para os gatilhos. O card {AUD-68} foi reconciliado no mesmo dia: ele apontava para o RF-CONV-054, que não o reprova, e prescrevia um conserto que o planejamento recusa por escrito (resolver o nome da tag em tempo de execução), porque faria o sintoma sumir deixando as outras vinte rotas mentindo. Quatro cards novos nasceram deste planejamento: {AUD-74} (a tela oferece duas ações que o motor não executa, e a que funciona não é oferecida: é o {AUD-43} de novo, agora nas ações), {AUD-75} (o modelo pronto entrega automação quebrada em um clique), {AUD-76} (a ação de enviar fatura não emite fatura e ainda registra que emitiu) e {AUD-77} (a condição não ramifica e criar tarefa está desativada). O momento é o mais barato que este conserto vai ter na vida do produto: o tenant piloto não tem automação nenhuma, e as duas automações ativas são de uma empresa de teste, então não existe automação de cliente real para quebrar. Quando houver, o mesmo commit teria que ser negociado com um cliente real. O {AUD-68} foi entregue em 2026-07-16 (commit 67224ec, merge 06e9724): o executor passou a derivar o desfecho de cada uma das vinte e uma rotas do que a rota de fato faz, em vez de assumir sucesso pela ausência de erro. Gates plan APPROVED, qa PASS, review APPROVED. O qa provou os sete discriminadores do H1 por efeito real no banco (concluído com efeito real, ignorado que segue por dado ou canal ausente, falha que para por configuração inválida ou ação que o motor não executa) e achou, de quebra, uma regressão restrita a um único workflow interno de dogfooding, sem alcance a cliente pagante, que virou o {AUD-78}. O review achou, fora do escopo da fatia, que a superfície de dado pessoal em log cresceu de um para cerca de doze pontos de escrita, anexado ao {AUD-69} já existente. O próximo item acionável da fila volta a ser o {AUD-57} (o agendamento público cria contato sem disparar automação): o {AUD-68} era escopo cravado por decisão direta do Wladimir e furou a fila por isso, não porque fosse o próximo por ordem.
Smoke visual real de 2026-07-16 (sessão viva em produção, modo claro e modo escuro) confirma o {AUD-68} na tela: a execução do "Welcome + Tag" aparece Falhou com o erro nomeado, e a Taxa de sucesso (30d) mostra 42,9% (6 de 14). O mesmo smoke revelou dois cards novos, {AUD-79} (o painel de automações conta zero workflows ativos com dois ativos na lista ao lado) e {AUD-80} (o nome do contato está vazio em 100% dos registros do tenant piloto, raiz que amplia o {AUD-61}), ambos ao final da Onda AUD. O próximo item acionável da fila passa a ser a fase F0 da sequência decidida no {AUD-65} (o council rodou em 2026-07-16 e a decisão está registrada naquele card); os dois cards novos entram na fila por prioridade, não furam.
Sessão de 2026-07-16 (segunda parte), reconciliação de texto: nenhuma linha de código de produto foi escrita. Esta sessão não entregou fatia nenhuma, e o que ela fez foi conferir no banco e no código o que os cards já publicados afirmavam. Três deles afirmavam fato falso e foram corrigidos aqui. (1) O {AUD-65} dizia "dezoito criam contato, só quatro emitem" e, na mesma frase, "treze mudos": os números não fechavam, porque a varredura procurou o nome do emissor do backend e não viu o emissor do frontend. São cinco emissores e treze mudos, e agora o conjunto fecha. Na terceira parte desta mesma data o quinto emissor deixou de ser dedução: foi medido em produção e emite de verdade. (2) O mesmo {AUD-65} mandava copiar o desenho dos webhooks de saída como se ele estivesse provado inteiro: a emissão está (3616 notificações), a entrega nunca rodou em tráfego real (zero enfileiradas, seis entregas de teste em maio, as assinaturas desligadas ou com filtro vazio), e "nunca perdeu um" é indistinguível de "nunca entregou nenhum". (3) O {AUD-80} se chamava "o nome está vazio em todos os registros": falso, 25 dos 25 contatos de canal vivo têm nome; o que existe é uma divisão limpa por caminho, a carga em lote de maio preenche uma coluna e todo canal vivo preenche a outra. O diagnóstico de fundo dos três continua de pé; o que mudou foram os fatos que os sustentavam. Nasceram seis cards, {AUD-81} a {AUD-86}, todos de defeito medido e nenhum de suposição, e o RF-AUTO-006 foi emendado para reprovar o {AUD-75}, que até hoje era um card que requisito nenhum reprovava.
O {AUD-57} NÃO foi executado nesta sessão, e a decisão é fundamentada. Ele era o próximo da fila, e não foi aberto de propósito: ele é sintoma, não raiz, e o próprio {AUD-65} manda decidir a arquitetura antes de abrir os doze pontos mudos um por um, porque a casa pagaria doze vezes um conserto que o desenho certo faria uma vez. O council do {AUD-65} rodou em 2026-07-16, convergiu, e a decisão está TOMADA e registrada no próprio card: o motor ganha exaustividade por construção para o fato contato criado, por gatilho no banco consumido pela fila que já existe, com sequência obrigatória de fases (medir a emissão da tela, chave de idempotência, salvaguardas com desligamento geral e listas de permissão, o gatilho, e só então remover os emissores antigos). Com a raiz decidida, o {AUD-57} deixa de ser o próximo item por si: ele migra para o desenho novo junto com os doze do {AUD-66}, em vez de ganhar correção pontual. Além disso a sessão achou um acoplamento que precisa ficar em ata: o {AUD-65} e o {AUD-80} são incompatíveis na mesma janela, porque o conserto do nome é uma atualização em massa em 1503 contatos e o gatilho de notificação já dispara em atualização; sem lista de permissão por tipo de evento, o card que conserta o nome vira o card que dispara automação para 1438 contatos reais.
Sessão de 2026-07-16 (terceira parte), a primeira medição que fechou um placar, e o que ela destravou. Esta sessão entregou o {AUD-82}: o mesmo fato disparado três vezes passou a gerar uma execução por automação, e não três, e quatro automações distintas ficaram com exatamente uma execução cada depois de o serviço reiniciar. O RNF-003 sai de violado por construção e passa a cumprido. O limite precisa ficar escrito, porque é o tipo de coisa que vira folclore: a chave protege contra a mesma coisa acontecer duas vezes, e NÃO protege contra o aviso se perder no caminho, porque o salto do banco até o ouvinte continua sem garantia. Ninguém pode vender a F3 do {AUD-65} como durabilidade resolvida por causa desta entrega.
Com a F1 cumprida, a F3 deixa de estar PROIBIDA pela falta da chave, e é só isso que mudou na ordem: ela continua atrás da F2 e da F2.bis, que são as salvaguardas, e essas não foram entregues. A F0 também fechou: o cadastro rápido de contato foi exercitado em produção e avisa o motor de verdade, com resposta de sucesso e o evento registrado no servidor. O quinto emissor era dedução e virou medição, e com isso o placar de cinco emissores do {AUD-65} está fechado por medição, e não por leitura de código. O defeito próprio daquele emissor continua real, mas mudou de natureza: ele engoliria uma recusa em silêncio, o que é risco latente e não falha viva, e por isso o {AUD-85} caiu de prioridade alta para média e a dúvida "será que emite?" saiu do card, respondida. Também se confirmou o {AUD-75} pelo lado que faltava: às 15:39 daquele dia o passo do modelo falhou com o motivo nomeado, em produção, o que prova de uma vez que o modelo curado entrega automação que não funciona E que o {AUD-68} está funcionando, porque o registro ficou honesto.
A F2.bis cresceu, e essa é a mudança de trabalho desta sessão. Ela era um emissor e virou o conjunto inteiro: quatro pontos do produto despacham whatsapp e nenhum deles decide pelo estado real do canal. Um pergunta por uma informação de estado que não existe e por isso nunca envia; os outros três seguem em frente sem olhar o estado do canal e sempre enviam, e um deles nunca tinha sido listado em card nenhum. A raiz é que não existe um lugar único que responda "esta empresa tem whatsapp utilizável?", então cada ponto refaz a conferência à sua maneira ou esquece dela, e é por isso que quatro pontos erraram de quatro jeitos diferentes. O {AUD-83} foi reescrito para cobrir o conjunto e para mandar criar esse lugar único, que é o que mata os casos de uma vez, e o {AUD-84} ficou irmanado a ele, porque consertá-lo sozinho LIGA um canal que está morto desde sempre. Nasceram dois cards: o {AUD-87}, um modelo aplicado que pode deixar a automação criada e vazia sem avisar ninguém, e o {AUD-88}, que endurece o requisito de honestidade do envio até ele reprovar o robô de conversa, hoje o único despachante que requisito nenhum reprova.
A F3 e a F4 do {AUD-65} foram entregues, e o motor de automação virou exaustivo por construção para o fato contato criado (2026-07-17). Um gatilho no banco, depois de cada inserção de contato, notifica um canal próprio, e a fila que já existe consome esse aviso e chama o emissor de eventos de sempre por um endpoint interno fail closed, sem nunca criar execução direto. Medido: um contato inserido direto no banco, sem nenhuma linha de código que anuncie o fato, dispara a automação, que é justamente o que a disciplina não garantia. Os cinco emissores antigos foram removidos um a um, cada um provado a seguir disparando só pelo gatilho, e não sobrou nenhum fora do trilho novo. A chave geral do motor, que shipou desligada, foi LIGADA em 2026-07-17 sob observação e com GO explícito do Wladimir, depois que o {AUD-100} foi resolvido, para o motor não estrear com automação quebrada. Prova de estreia: um contato de prova gerou duas execuções e o "Welcome + Tag" completou aplicando a tag de verdade. O escopo efetivo segue contido: a lista de organizações permitidas tem só a organização de teste (a Hiit segue fora por ausência de automação), a lista de eventos permitidos só tem contato criado, e o teto é de sessenta disparos por hora. Dois limites ficam declarados e não podem sumir: só o fato contato criado é por construção, os demais fatos seguem por disciplina e o {AUD-85} continua aberto; e o salto do gatilho até o ouvinte é dispare e esqueça, agora sem o cinto e suspensório que os emissores antigos davam, o que faz nascer o card de caixa de saída, o {AUD-99}. Um segundo card, o {AUD-100}, foi resolvido no mesmo dia: a única instância de automação com a configuração legada quebrada (um passo do "Welcome + Tag" da organização de teste) teve o nome da tag resolvido para o identificador e passou a aplicar a tag de verdade. O próximo item acionável da fila segue a ordem do próprio roadmap.
O {AUD-32} foi entregue em 2026-07-17 (merge 1ec9c8d, migration 094), o primeiro card aberto da fila na ordem do documento. O modo entrar como empresa do Super Admin passou a alcançar todo o canal /api do webhook: um auxiliar único no servidor honra a marca somente quando quem chama é Super Admin e foi aplicado nos cinco pontos que resolviam a empresa pela identidade do usuário; o frontend ganhou um ponto único de chamada que injeta a marca em toda requisição autenticada (37 chamadas roteadas, 11 públicas intocadas de propósito); os três repasses de links rastreáveis encaminham a marca; e a função do banco que cria o link rastreável passou a honrar a marca e ficou determinística. As provas foram em produção, com par positivo e negativo: a listagem de Caixas de Email deixou de vir vazia no modo, o link criado nasce na empresa escolhida e aparece na própria lista, membro comum forjando a marca não escala privilégio, e quem não é membro nem Super Admin segue bloqueado. A validação ainda achou e a própria fatia corrigiu um defeito irmão do {AUD-27}: a rota de gerar código Pix de fatura exigia um prefixo que o servidor de borda remove, então estava morta para qualquer usuário desde que nasceu; agora responde e foi exercitada de ponta a ponta em produção. Fronteira honesta: os dois endereços do canal alternativo de whatsapp seguem mortos para todos pelo defeito próprio do {AUD-96}, que já tem o auxiliar aplicado e passa a valer quando aquele card os religar. O {AUD-33} foi entregue em 2026-07-18 (merge eb2e875, migration 095): os cards Usuários e Contatos do painel da agência passaram a contar só as empresas reais, por função agregada com gate de Super Admin, e o valor deixou de variar conforme a empresa ativa. Da medição desta fatia nasceu o {AUD-101} (os gráficos das abas SaaS e Atividade contam empresas de teste, mesma família). O próximo card aberto da fila na ordem do documento é o {AUD-36}.
Sessão de 2026-07-18, o controle de acesso por papel virou produto de verdade, das três telas divergentes até a tela que o administrador usa. Três cards fecharam em sequência. O {AUD-38} (merge 3670d2f) fixou o catálogo canônico de treze módulos como fonte única no código e no requisito, e alinhou sete telas que perguntavam a permissão pelo módulo errado (Tarefas, Produtos e Formulários pediam Contatos, Automações pedia um módulo inexistente, Relatórios ganhou módulo próprio, Campanhas entrou com a ação de enviar, Caixas de Email passou a exigir Configurações). O {AUD-37} (merge d821fec) entregou a tela de Papéis e Permissões em Configurações, restrita a dono e administrador, com a grade de módulos e ações desenhada a partir do mesmo catálogo, criar, editar e excluir papel, e a atribuição de papel na tela de Minha Equipe, mais a migration 096 que fechou uma auto-escalação (qualquer membro escrevia na tabela de papéis, agora só dono e administrador). O qa reprovou a primeira rodada do {AUD-37} porque o banco recusava a escrita negada só em seis módulos: nasceu daí o {AUD-38b} (migration 097, mesma entrega), que estendeu o reforço às tabelas de Tarefas, Produtos, Formulários, Campanhas, orçamentos e cupons, provado ao vivo com token de membro real. O smoke real confirmou a tela em produção, claro, escuro e a 375px, sem rolagem horizontal. Próximo card aberto na ordem do documento é o {AUD-36}, o reforço de ver e exportar, agora exercitável porque a tela de papéis existe. Ainda nesta sessão, o planejamento do {AUD-37} havia revelado um defeito de segurança na regra de escrita de membros de empresa, que virou o {AUD-103} e foi entregue no mesmo dia (merge f6b3bfd, migration 098): um ramo escrito comparando uma coluna consigo mesma permitia que um usuário sem nenhum vínculo de empresa se inserisse como dono de qualquer empresa, e o ramo foi removido, deixando a escrita só para dono e administrador.
Sessão de 2026-07-19, o {AUD-36} fechou e o reforço de acesso por papel chegou à leitura. O {AUD-36} foi entregue (merge 151fef5, migration 099): a permissão de ver deixou de valer só na tela e passou a valer no banco, com quinze regras restritivas de leitura, uma por tabela, exigindo que o papel libere o módulo, nas mesmas quinze tabelas do mapa de escrita do {AUD-29} e do {AUD-38b}. Os dois medos do card foram refutados por medição: as páginas públicas leem por um caminho de servidor com acesso próprio e não caem, e os encaixes de dado de outro módulo foram mapeados, a linha-mãe sobrevive com o campo aninhado em branco em vez de a consulta voltar vazia em silêncio. Recorte declarado: exportar não tem endereço de servidor próprio, colapsa em ver no banco, e o delta ver-liberado com exportar-negado segue só na tela. Provado por qa com acesso de membro de papel restritivo (zero linhas em contatos, oportunidades e conversas onde existiam dezenove, dois e dez; dono, administrador, membro sem papel e Super Admin intactos; públicos funcionando), gates verdes e smoke visual real. Do qa desta fatia nasceu o {AUD-104}, fora do escopo do card: o Super Admin sem vínculo na subconta não cria papel pela tela e o botão trava em Salvando; está catalogado ao fim da Onda AUD. Nesta sessão o {AUD-38c} e o {AUD-38d}, que restavam como pendência de catalogação, entraram como cards da Onda AUD, cada um com o seu recorte do reforço de escrita que falta. Ainda em 2026-07-19 o {AUD-38c} também fechou (merge a7c92e1, migration 100): o reforço de escrita chegou às vinte e uma tabelas acessórias dos próprios módulos, com cinquenta e duas regras restritivas, junções protegidas pela permissão de editar da entidade mãe, captura pública de formulário intacta e os oito botões de excluir das telas alinhados à permissão. O próximo card aberto da fila na ordem do documento é o {AUD-38d}, os módulos de configuração e administração.
Sessão de 2026-07-19 (segunda parte), o {AUD-38d} fechou e o reforço de escrita por papel chegou aos módulos de configuração e administração. O {AUD-38d} foi entregue (merge cd5efd2, migration 101): vinte e sete regras restritivas de escrita em nove tabelas de Configurações e Administração, cada uma exigindo que o papel libere editar o módulo. O recorte real foi reconciliado com a medição: das onze tabelas nomeadas no título, nove foram gateadas e duas ficaram de fora por construção (snapshots e aplicações de snapshot, recurso do fornecedor, sem empresa dona, já restrito a Super Admin). Ficou registrada a nota honesta de que só quatro das nove têm efeito exercitável hoje (campos personalizados, integrações, SMS e WhatsApp) e as outras cinco são reforço defensivo, exaustivo por construção, sobre tabelas que dono e administrador já cobriam. Provado por qa com token de membro de papel restritivo de verdade, telas alinhadas ao gating de editar, caminhos de servidor imunes. Da medição nasceram dois cards ao fim da Onda AUD: o {AUD-105} (a leitura de Configurações e Administração ainda não é reforçada por papel no banco, gap que o {AUD-36} deixou fora ao cobrir só as quinze tabelas operacionais) e o {AUD-106} (o padrão do membro sem papel libera editar Administração por omissão, ao contrário de Configurações; decisão tomada em 2026-07-22, negar por simetria, o card virou o fix da migration 103). O {AUD-39} fechou nesta sessão (2026-07-19, merge 1c916d2, migration 102): a regra pública cega de leitura de calendários foi removida, e a leitura da biblioteca de modelos de automação passou a exigir login, com rascunho restrito ao Super Admin, provada por três identidades. O {AUD-41} fechou em 2026-07-22 (migration 103, merge 83cc7a0): a empresa deixou de ser provisionada sozinha ao criar um usuário.
Sessão de 2026-07-22 (S25), o {AUD-41} e o {AUD-107} fecharam. Migration 103 aplicada no banco do ModularCRM: o gatilho que, a cada usuário criado, criava perfil, empresa e posse dela junto, passou a criar só o perfil; o provisionamento de empresa ficou explicito, só pelo assistente do Super Admin, que já era o caminho oficial. O comentário do convite de membro foi corrigido para não prometer o que o código não faz. Entregue, qa PASS e review APPROVED (gates na VPS), merge 83cc7a0 em main, webhook reiniciado (200), smoke do painel de Subcontas confirmando só a Hiit Fitwear como cliente real e o painel sem tela branca. Na sequência, irmã do mesmo dia, o {AUD-107} fechou a porta da tela e do sistema de login que o {AUD-41} deixou aberta: GoTrue com auto-cadastro desligado (DISABLE_SIGNUP=true, recreate só do mcrm-auth, provado com 422 signup_disabled e convite por token de serviço funcionando com o auto-cadastro desligado), frontend sem a página pública de criar conta (redirecionamento para o login, CTAs removidos e repontados, smoke visual real na página de apresentação e na tela de entrada), migration 104 removendo a função generate_slug (zero chamador, rollback LIFO), qa PASS e review APPROVED (gates na VPS), merge b121c7d em main, site respondendo 200. Ainda no mesmo dia, a construção da Onda C-MCRM começou: a primeira sub-fatia do {C-MCRM-2} (conexão Meta permanente) entregou a etapa de configuração do aplicativo Meta (migration 105, merge e3a523e), com as sub-fatias 2 a 4 seguindo pendentes. Sessão de 2026-07-23 (S27), a sub-fatia 2 do {C-MCRM-2} fechou. O caminho primário de conexão com a Meta passou a ser o Login do Facebook para Empresas pelo aplicativo dedicado, com o tipo do acesso decidido perguntando à própria Meta em vez de assumido, e a validação de assinatura dos webhooks deixou de falhar aberta. Provado com clique real na tela de Integrações em produção. Merge f63ba42 em main, qa PASS e review APROVADO com comentários (gates na VPS), site respondendo 200 e nada de outro projeto na máquina afetado. O card {C-MCRM-2} segue em aberto porque as sub-fatias 3 e 4 não entraram. Nasceu o {AUD-109} a partir do olhar na tela.
Sobre o {AUD-42} (2026-07-23): o mecanismo que ele pedia está construído e no ar (sonda de hora em hora, estado honesto na tela, painel de saúde), mas o card segue em aberto por honestidade: o estado "expirada" nunca foi observado de verdade, porque provocá-lo exigiria invalidar a credencial viva de um cliente real. Está coberto por leitura de código e pelos dois gates, não por observação. Fecha de fato quando uma conexão real vencer ou quando a migração para o aplicativo novo criar uma janela segura de teste.
A fila seguinte, na ordem do documento: {AUD-104} → {AUD-105} → {AUD-106} → {AUD-108}. (O {AUD-44} e o {AUD-45} fecharam em 2026-07-24; o {AUD-109} fechou na S27. Nasceram o {AUD-110} e o {AUD-111} do planejamento do {AUD-45}.)
Cada tarefa é um card com um estado e um "Como verificar". Marcação: [x] concluído e em produção, [ ] pendente na retomada.
Planejamento (Fase 0)
Concluída na aprovação do DRS. Reúne o trabalho de elicitação, especificação e definição de escopo.
Fase M, Mockup Navegável
Etapa padrão pós-planejamento e pré-construção. Como o sistema já foi construído e está em produção, esta fase é retroativa: a referência visual é o produto em produção mais a paridade GHL, não um protótipo estático.
Fase 1, Pilares Core
1.1 Captura de Leads
1.2 Gestão de Leads
1.3 Conversas e Inbox
1.4 Experiência e Interface
Fase 2, Módulos Secundários
Fase 3, API Pública e Integrações
Fase 4, Habilitação do Tenant Piloto (retomada)
Ações operacionais para deixar a Hiit Fitwear 100% operacional. São o primeiro bloco da retomada.
Fase 5, Polimento e Evolução
Fase 6, Paridade GoHighLevel (backlog)
Backlog de paridade com o GoHighLevel, recortado em 2026-07-10 ao escopo real do produto (painel interno da Modulareasy, isolamento por subconta, sem revenda white-label). Cada card é uma área; o detalhe requisito a requisito, com H1, está na subseção do DRS. Sem data: é direção de produto, a priorizar por você. Retiradas do backlog: Telefonia, marketplace de desenvolvedores, Cursos e comunidades, Sites institucionais, Funis e Loja, e a parte de revenda do modo Agência.
Onda AUD, Correções da auditoria (2026-07-10)
Achados do walkthrough tela a tela de 2026-07-10, agora no formato de fatia executável: cada card traz sintoma, causa provável, o que fazer, como verificar e o aceite (H1). São correções do que já existe, não funcionalidades novas. Estão ordenados por prioridade: primeiro a segurança e os bloqueios de alto impacto (AUD-14, 01, 02, 07, 03, 04), depois os defeitos de tela de média prioridade (05, 06, 09, 08, 10), por fim o polimento (11, 12, 13). Cada card é uma fatia: branch própria, planner gate antes de codar, qa + code-reviewer, smoke visual real na tela afetada, e o checkbox só vira [x] com o aceite 100% cumprido. Pegar sempre o primeiro card [ ] na ordem abaixo.
Segurança e bloqueios de alto impacto
- Prioridade: P0 (segurança). RFs: RF-INT-005, RNF-002. Branch: fix/AUD-14-token-meta-cifrado.
- Sintoma: o token de página da Meta aparece em texto puro nos metadados da integração no banco.
- Causa provável: a cifragem em repouso cobriu o token principal, mas não o campo de metadados que também guarda token.
- O que fazer: passar o campo de metadados do token pela mesma camada de cifragem em repouso já usada no token principal (grava cifrado, decifra só no uso); migrar os registros existentes que estão em texto puro; garantir que nenhuma leitura ou log devolve o token em claro.
- Como verificar: varrer a tabela de integrações e confirmar que nenhum token aparece em texto puro; o envio/uso da integração continua funcionando lendo pela camada de cifragem.
- Aceite (H1): Dado a integração Meta de uma empresa, Quando o token é gravado e lido, Então fica cifrado em repouso e só é decifrado no momento do uso, E uma varredura no banco não encontra nenhum token em claro.
- Prioridade: alta. RFs: RF-AGY-016. Branch: fix/AUD-01-super-admin-entrar-como.
- Sintoma: o Super Admin, ao entrar numa empresa para dar suporte, vê painel zerado e listas vazias mesmo havendo dados.
- Causa provável: a política de isolamento por linha (RLS) não abre exceção para o Super Admin no contexto "entrar como", então filtra tudo.
- O que fazer: dar ao Super Admin, quando em modo "entrar como", leitura escopada à empresa selecionada (exceção controlada na RLS ou troca de contexto de sessão para o org_id alvo), sem afrouxar o isolamento entre as demais empresas. Registrar o acesso.
- Como verificar: entrar numa empresa com dados e ver os contatos, conversas e oportunidades reais dela; sair do modo restaura a visão global; um usuário comum de outra empresa continua sem enxergar nada fora da sua.
- Aceite (H1): Dado um Super Admin em modo entrar como a empresa X, Quando abre contatos, conversas e funil, Então vê os dados reais da empresa X, E ao sair volta à visão global sem vazar dados de X para outra empresa.
- Prioridade: alta. RFs: RF-CONV-054, RF-CONV-002. Branch: fix/AUD-02-envio-sem-canal.
- Sintoma: enviar mensagem numa empresa sem canal ativo cria a bolha e grava "enviada" no banco, sem despachar nada e sem avisar. Raiz da percepção "conectado mas nada chega".
- Causa provável: o envio persiste a mensagem como enviada antes (ou independentemente) de confirmar que há canal ativo e que o despacho ocorreu.
- O que fazer: antes de marcar "enviada", validar que existe canal conectado para aquele tipo; sem canal, bloquear com aviso claro ou registrar como falha; refletir o status real de entrega (falha/pendente) vindo do provedor, nunca otimista.
- Como verificar: tentar enviar sem canal conectado bloqueia ou marca falha com aviso; com canal, o status reflete a entrega real; nenhuma mensagem não despachada fica como "enviada".
- Aceite (H1): Dado uma empresa sem canal conectado, Quando o operador tenta enviar, Então recebe aviso claro e a mensagem não é registrada como enviada, E quando há canal, o status exibido corresponde ao resultado real do despacho.
- Prioridade: alta. RFs: RF-BILL-002, RF-AGY-003. Branch: fix/AUD-07-vinculo-plano.
- Sintoma: o tenant piloto aparece como plano pago na tela, mas não tem vínculo com o cadastro de planos, cai nos limites mínimos (um único membro) e nunca gerou fatura.
- Causa provável: a empresa guarda um rótulo de plano solto em vez de referência ao registro de plano; a rotina de faturamento e os limites leem a referência ausente.
- O que fazer: vincular a empresa ao registro de plano correto (referência íntegra); fazer os limites e a geração de fatura lerem esse vínculo; corrigir o dado do piloto e prevenir empresa com plano sem vínculo.
- Como verificar: a empresa com plano pago tem o vínculo correto, respeita os limites do plano (ex: nº de membros) e gera fatura no ciclo.
- Aceite (H1): Dado uma empresa marcada como plano pago, Quando os limites são aplicados e o ciclo de cobrança roda, Então ela respeita os limites do plano vinculado, E uma fatura é gerada para o período.
- Prioridade: alta. RFs: RF-CAL-002, jornada {B-06}. Branch: fix/AUD-03-agendamento-publico.
- Sintoma: a página pública exibe "Calendário não encontrado" mesmo para calendário válido e ativo.
- Causa provável: a consulta da página pública pede campos que não existem no schema atual e falha.
- O que fazer: alinhar a consulta aos campos reais do calendário/disponibilidade; tratar o caso de calendário inexistente separado do erro de consulta; smoke do link público real.
- Como verificar: abrir o link público de um calendário ativo mostra os horários disponíveis e permite agendar, criando o agendamento vinculado a um contato.
- Aceite (H1): Dado um calendário ativo, Quando um visitante abre o link público, Então vê os horários e consegue agendar, E o agendamento aparece no sistema vinculado a um contato.
- Prioridade: alta. RFs: RF-CONV-012. Branch: fix/AUD-04-chat-publico.
- Sintoma: a página pública de chat e o widget incorporável não funcionam; a rota do serviço responde a página do aplicativo em vez do serviço de chat.
- Causa provável: o serviço/rota de chat público não está publicado no servidor (faltando no build/deploy ou na configuração do Nginx).
- O que fazer: publicar e rotear o serviço de chat público corretamente (deploy do serviço + regra de rota no servidor); validar a página pública e o widget de ponta a ponta.
- Como verificar: abrir a página pública de chat de uma empresa carrega o chat; o widget incorporado num site externo inicia conversa que cai no inbox.
- Aceite (H1): Dado o chat público de uma empresa, Quando um visitante inicia uma conversa pela página ou pelo widget, Então a conversa é criada e aparece no inbox da empresa, E o operador consegue responder.
- Prioridade: alta (segurança). RFs: RNF-004, RF-CONV-054. Branch: fix/AUD-26-endpoints-sem-auth.
- Sintoma: três rotas do servidor de integrações executam ação sem exigir token de usuário, envio de campanha, envio de SMS e convite de membro, permitindo que uma chamada externa dispare envio ou convite em nome de uma empresa.
- O que fazer: exigir autenticação e reconhecimento de acesso à empresa (mesmo padrão do {AUD-15}: membro da empresa ou Super Admin) antes de qualquer ação, sem afrouxar o isolamento.
- Como verificar: chamada sem token é recusada (401); usuário comum não-membro é recusado (403); membro da empresa e Super Admin conseguem; nenhum envio/convite ocorre sem autenticação.
- Aceite (H1): Dado um endpoint de ação do servidor, Quando chamado sem autenticação ou por quem não tem acesso à empresa, Então a ação é recusada, E só membros da empresa ou o Super Admin conseguem executá-la.
Defeitos de tela (média prioridade)
- Prioridade: média. RFs: seção 11.9 (RF-AGY). Branch: fix/AUD-05-aba-saas.
- Sintoma: abrir a aba "SaaS" no painel da agência quebra a aplicação por leitura de valor nulo.
- Causa provável: a tela acessa um campo de um objeto que pode vir nulo, sem guarda.
- O que fazer: proteger a leitura (guarda de nulo/estado vazio) e mostrar estado vazio quando não houver dado. Observação de escopo: a revenda SaaS foi cortada do produto; se a aba não fizer sentido no modelo interno, a correção pode ser remover/ocultar a aba em vez de consertá-la (confirmar no DRS antes).
- Como verificar: a aba "SaaS" abre e mostra os indicadores (ou um estado vazio limpo) sem erro; ou não aparece mais, conforme decisão de escopo.
- Aceite (H1): Dado o painel da agência, Quando o operador abre a aba SaaS, Então a tela carrega sem quebrar, E exibe os dados ou um estado vazio claro.
- Prioridade: média. RFs: RF-AUTO-006. Branch: fix/AUD-06-templates-workflow.
- Sintoma: a tela de modelos de automação da agência quebra ao tratar a lista de modelos.
- Causa provável: tratamento da lista assume formato/campo que pode faltar.
- O que fazer: tornar o tratamento da lista resiliente (guarda de nulo, estado vazio) e validar com lista vazia e com itens.
- Como verificar: a tela abre e lista os modelos sem erro, inclusive quando não há modelo.
- Aceite (H1): Dado a tela de modelos de automação, Quando é aberta com zero ou vários modelos, Então lista sem quebrar, E permite abrir um modelo.
- Prioridade: média. RFs: RF-OPP-002. Branch: fix/AUD-09-criar-oportunidade-rota.
- Sintoma: o botão de criar oportunidade a partir do contato navega para um endereço que não existe e cai em "página não encontrada".
- Causa provável: rota/link incorreto ou tela de criação não existente a partir desse ponto.
- O que fazer: apontar o botão para o fluxo real de nova oportunidade, já pré-vinculada ao contato de origem.
- Como verificar: o botão abre o fluxo de nova oportunidade com o contato já vinculado; ao salvar, a oportunidade aparece no funil ligada ao contato.
- Aceite (H1): Dado a ficha de um contato, Quando o operador clica em criar oportunidade, Então abre o fluxo de nova oportunidade vinculada a esse contato, E ao salvar ela consta no funil ligada a ele.
- Prioridade: média. RFs: RF-LEAD-002. Branch: fix/AUD-08-encoding-ficha.
- Sintoma: rótulos da ficha do contato aparecem com acentuação quebrada (caracteres corrompidos).
- Causa provável: problema de codificação (UTF-8) no build ou na fonte dos textos daquela tela.
- O que fazer: corrigir a codificação na origem (arquivo/fonte de textos e pipeline de build) para UTF-8 correto; conferir que não é caso isolado da ficha.
- Como verificar: a ficha mostra "Responsável", "Ações", "Endereço" e demais rótulos corretos, sem símbolos estranhos, em produção.
- Aceite (H1): Dado a ficha do contato em produção, Quando é aberta, Então todos os rótulos acentuados aparecem corretos, E o mesmo vale nas telas que reusam esses textos.
- Observação do teste: o texto fixo da LGPD no card de consentimento é legível mas sem alguns acentos (não é codificação corrompida); registrado sem card próprio.
- Prioridade: média. RFs: RF-PERM-030, RNF-006. Branch: fix/AUD-10-audit-log.
- Sintoma: a tela de "Registro de auditoria" fica vazia mesmo após criar, editar e apagar registros.
- Causa provável: as ações não estão sendo escritas na trilha de auditoria (gravação ausente ou não disparada).
- O que fazer: gravar as ações relevantes (criar/editar/apagar de entidades chave) na trilha de auditoria com autor, tipo, entidade e data; a tela lê e lista por empresa.
- Como verificar: após executar ações, elas aparecem no registro com autor, tipo e data, escopadas à empresa.
- Aceite (H1): Dado um operador que cria, edita e apaga registros, Quando abre o registro de auditoria, Então vê essas ações com autor, tipo e data, E o registro respeita o isolamento por empresa.
Polimento (baixa prioridade)
- Entregue 2026-07-12 (merge e991e03): a sub-navegação de Configurações passou a seguir o tema (clara no modo claro, escura no escuro) usando os tokens do sistema, e em telas estreitas virou um seletor no topo, deixando o conteúdo ocupar a largura inteira sem espremer.
- Prioridade: baixa. RFs: RF-UX-001, RNF-007. Branch: fix/AUD-20-settings-theme-mobile.
- Sintoma: em Configurações o modo claro não aplica na sub-navegação nem no conteúdo (só a barra de busca clareia) e em 375px a sub-navegação não colapsa, espremendo o conteúdo.
- Causa provável: pré-existente à onda AUD (reproduzido em abas não tocadas por esta onda), os tokens de tema claro/escuro não cobrem toda a sub-navegação e o conteúdo da seção, e a sub-navegação não tem comportamento responsivo para telas pequenas.
- O que fazer: aplicar os tokens de tema consistentemente na sub-navegação e no conteúdo de toda a seção de Configurações; dar à sub-navegação um comportamento responsivo em 375px que não espreme o conteúdo.
- Como verificar: alternar para tema claro em qualquer aba de Configurações mostra sub-navegação e conteúdo claros, não só a busca; abrir Configurações em 375px mostra a sub-navegação adaptada sem espremer o conteúdo.
- Aceite (H1): Dado a seção de Configurações, Quando o tema é claro, Então a sub-navegação e o conteúdo aplicam o tema claro, E quando a tela é 375px a sub-navegação não espreme o conteúdo.
- Prioridade: baixa. RFs: RF-LEAD-002. Branch: fix/AUD-21-merge-suggestions-403.
- Sintoma: ao abrir a ficha do contato o console mostra GET /api/contacts/:id/merge-suggestions com 403; a sugestão automática de duplicados não funciona, sem quebra visível na interface.
- Causa provável: o endpoint de sugestões de mesclagem exige um contexto de autenticação ou escopo que a chamada feita pela ficha do contato não está enviando corretamente.
- O que fazer: alinhar a autenticação/escopo da chamada de sugestões de mesclagem ao mesmo contexto usado pelo resto da ficha do contato (mesma empresa, mesmo token), sem afrouxar a validação de isolamento.
- Como verificar: abrir a ficha de um contato não gera 403 no console para o endpoint de sugestões; quando existe duplicado plausível, a sugestão aparece.
- Aceite (H1): Dado a ficha de um contato, Quando a tela carrega, Então a chamada de sugestões de mesclagem retorna 200, E sugestões reais de duplicado aparecem quando existem.
- Fechado 2026-07-13 (destravado por {AUD-22} + {AUD-30}): além do 403 já corrigido, o Super Admin agora vê a sugestão real de duplicados E consegue mesclar de fato (a mesclagem estava quebrada, corrigida no {AUD-30}), provado ponta a ponta com o Super Admin entrando como a empresa e concluindo a mesclagem.
- Prioridade: baixa. RFs: RF-TASK-001, RF-OPP-002. Branch: fix/AUD-11-modais-fecham.
- Sintoma: as janelas de nova tarefa, nova oportunidade e novo produto ficam abertas com os dados após salvar, arriscando criação duplicada.
- Causa provável: o sucesso do salvar não dispara o fechamento nem a limpeza do formulário.
- O que fazer: ao salvar com sucesso, fechar a janela, limpar o formulário e refletir o novo item na lista; prevenir duplo clique.
- Como verificar: ao salvar, a janela fecha e o item aparece na lista uma única vez.
- Aceite (H1): Dado uma janela de criação preenchida, Quando o operador salva com sucesso, Então a janela fecha e o item aparece uma única vez na lista, E um segundo envio acidental não cria duplicata.
- Prioridade: baixa. RFs: RF-UX-001. Branch: fix/AUD-12-i18n-config.
- Sintoma: em Configurações há rótulos em inglês ("Full Name", "Update Profile", "Add User", "Create tag", entre outros).
- Causa provável: textos hardcoded em inglês ou chaves de tradução faltando nessas telas.
- O que fazer: traduzir os rótulos para português nas telas afetadas; varrer Configurações por outros resíduos em inglês.
- Como verificar: todos os textos visíveis em Configurações (e telas vizinhas) estão em português.
- Aceite (H1): Dado as telas de Configurações, Quando o usuário as percorre, Então todos os rótulos estão em português, E não resta texto em inglês visível.
- Prioridade: baixa. RFs: RNF-005. Branch: fix/AUD-13-dados-teste.
- Sintoma: empresas fictícias de teste ("Empresa QA Teste", "Loja Flor de Liz") aparecem junto do tenant real.
- Causa provável: dados de teste criados direto em produção, sem separação nem marcação.
- O que fazer: por lista nominal conferida (nunca filtro amplo), remover ou marcar-e-ocultar os registros de teste; definir a prática de teste sem sujar produção (ambiente ou marcação). Confirmar cada id vivo antes de apagar.
- Como verificar: produção não exibe dados de teste; o tenant real aparece limpo.
- Aceite (H1): Dado a lista de empresas em produção, Quando um operador a consulta, Então só vê empresas reais, E nenhum registro de teste conhecido aparece.
- Prioridade: média. RFs: RF-AGY-016, RF-CONV-054. Branch: fix/AUD-15-impersonate-backend.
- Sintoma: o Super Admin em modo "entrar como empresa" vê os dados, mas ações que passam pelo servidor de integrações (ex: enviar e-mail) respondem "acesso negado", porque o servidor só reconhece as empresas de que o usuário é membro e ignora o modo ativo.
- Causa provável: os endpoints do servidor Node validam a empresa pelo vínculo de membro do token, sem considerar o cabeçalho do modo "entrar como" que o navegador envia.
- O que fazer: fazer o servidor de integrações reconhecer o modo (validando Super Admin e modo ativo com o mesmo rigor da regra de isolamento), sem afrouxar a validação para usuários comuns.
- Como verificar: em modo "entrar como", uma ação de servidor em nome da empresa (ex: enviar e-mail por canal conectado) funciona; um usuário comum continua restrito às empresas dele.
- Aceite (H1): Dado um Super Admin em modo "entrar como" a empresa X, Quando executa uma ação de servidor em nome de X, Então a ação respeita o escopo de X e funciona, E usuários comuns seguem restritos às suas empresas.
- Prioridade: baixa. RFs: RF-CAL-002, RNF-002. Branch: fix/AUD-16-hardening-agendamento.
- Sintoma: pontos de robustez apontados na entrega do {AUD-03}, nenhum quebra o fluxo hoje: a gravação aceita horário fora das janelas de disponibilidade (o site só oferece horários válidos, mas uma chamada direta à rota consegue gravar de madrugada); duas confirmações simultâneas do mesmo horário podem passar juntas (janela de corrida entre conferir e gravar); as rotas públicas de leitura não têm limite de chamadas por IP; o link de cancelamento usa o identificador do agendamento sem prazo de validade (o reagendamento já usa código com validade).
- O que fazer: validar a janela de disponibilidade também na gravação; trocar a conferência de conflito por garantia no próprio banco (restrição de exclusão por intervalo); aplicar o limite por IP já existente também nas leituras públicas; migrar o cancelamento para o padrão de código com validade do reagendamento.
- Como verificar: chamada direta fora da janela é recusada; duas gravações simultâneas do mesmo horário resultam em uma só; leituras públicas em rajada são limitadas; link de cancelamento vencido não cancela.
- Aceite (H1): Dado o agendamento público em produção, Quando alguém tenta gravar fora da janela, em corrida ou com link vencido, Então o sistema recusa com resposta clara, E o fluxo legítimo continua funcionando.
- Prioridade: baixa. RFs: RF-CONV-012. Branch: fix/AUD-17-hardening-chat-publico.
- Sintoma: pontos de robustez apontados na entrega do {AUD-04}, nenhum quebra o fluxo hoje: a leitura de mensagens por identificador de conversa não exige nada além do próprio UUID, sem escopar pelo visitante; os endpoints públicos do chat não têm limite de chamadas; a página pública não guarda a conversa ao recarregar (o histórico só reaparece depois de um novo envio, o widget já guarda); a marcação de mensagens como entregues roda a cada busca mesmo sem pendência.
- O que fazer: escopar a leitura de mensagens por conversa ao visitante dono dela; aplicar limite de chamadas nos endpoints públicos do chat; fazer a página pública guardar a conversa ativa como o widget já faz; só rodar a marcação de entrega quando houver mensagem pendente.
- Como verificar: leitura de conversa alheia por UUID adivinhado é recusada; rajada de chamadas nos endpoints públicos é limitada; recarregar a página pública mantém o histórico; a marcação de entrega não roda sem pendência.
- Aceite (H1): Dado o chat público em produção, Quando alguém tenta ler conversa alheia, ultrapassa o limite de chamadas ou recarrega a página no meio de uma conversa, Então o sistema recusa ou preserva o estado corretamente, E o fluxo legítimo continua funcionando.
- Prioridade: alta. RFs: RF-LEAD-002. Branch: fix/AUD-18-excluir-contato-409.
- Sintoma: ao excluir um contato que tem dependências no banco (ex: passos de automação agendados), o banco recusa (409) e a interface finge sucesso: volta para a lista sem aviso e o contato continua existindo.
- Causa provável: o fluxo de exclusão não trata o erro da API e navega incondicionalmente.
- O que fazer: dar semântica às cinco chaves estrangeiras que travavam a exclusão (migration 079): remover junto as automações agendadas e os envios de formulário do contato (dado pessoal, atende LGPD), anonimizar aberturas e cliques de campanha preservando as métricas agregadas, e desfazer a referência de contato mesclado sem travar; no frontend, tratar todo erro real do delete (inclusive falha de rede) com aviso claro mantendo o operador na ficha, confirmar o sucesso com aviso antes de voltar para a lista, aplicar o mesmo tratamento na exclusão em massa da listagem, e a janela de confirmação informar exatamente o que sai junto.
- Como verificar: excluir contato com automação agendada e envio de formulário remove o contato levando os registros junto, com aviso de sucesso; aberturas e cliques de campanha do contato ficam anônimos preservando as métricas; uma falha real (ex: rede) mostra o motivo e mantém o operador na ficha; a janela de confirmação lista o que será removido.
- Aceite (H1): Dado um contato com automações agendadas ou histórico vinculado, Quando o operador confirma a exclusão, Então o contato é removido levando junto automações agendadas e envios de formulário e anonimizando aberturas e cliques de campanha, E qualquer falha real mostra o motivo e mantém o operador na ficha.
- Prioridade: baixa. RFs: RF-OPP-002. Branch: fix/AUD-19-hardening-vinculo-org.
- Sintoma: nenhum visível na interface; achado de review da fatia {AUD-09}: o insert de oportunidade aceita um identificador de contato sem garantir que o contato pertence à mesma organização.
- Causa provável: falta gatilho/validação no banco garantindo que o contato da oportunidade é da mesma organização (a política de isolamento valida só a organização da própria oportunidade).
- O que fazer: gatilho de validação no banco (mesma classe do gatilho do {AUD-07}); na mesma fatia, revisar a permissão de criação que fica permissiva durante o carregamento do papel e o pedido de criação que se perde em silêncio quando a consulta de funis falha.
- Como verificar: tentativa de inserir oportunidade com contato de outra organização é rejeitada pelo banco; o fluxo normal segue funcionando.
- Aceite (H1): Dado um insert de oportunidade com contato de outra organização, Quando submetido por qualquer via, Então o banco rejeita, E o fluxo com contato da mesma organização continua funcionando.
- Entregue 2026-07-13 (merge d12c179, migration 086): a sugestão de mesclagem passou a comparar e-mail e telefone normalizados (colunas geradas email_norm/phone_norm com índices por organização), em vez de depender de identificadores compartilhados (que a unicidade por empresa tornava inertes); dois contatos da mesma empresa com o mesmo e-mail ou telefone agora aparecem como sugestão real, provado ponta a ponta na tela.
- Prioridade: média. RFs: RF-LEAD-002. Descoberto no QA da fatia {AUD-21} (2026-07-12).
- Sintoma: mesmo com o endpoint respondendo 200, a sugestão automática de duplicados nunca apresenta candidatos; a seção de sugestões da ficha fica sempre vazia.
- Causa provável: o casamento procura outro contato que divida o mesmo par (tipo, valor) de identificador dentro da empresa, mas a tabela de identificadores tem regra de unicidade (empresa, tipo, valor), então dois contatos da mesma empresa não podem dividir um identificador; o casamento por identificador compartilhado é estruturalmente inerte.
- O que fazer: decidir a abordagem no planejamento antes de codar: comparar diretamente os dados do contato (e-mail, telefone normalizado) em vez de depender de identificadores compartilhados, ou tratar o conflito de unicidade no momento da ingestão como sinal de duplicado; então implementar a detecção de duplicados de verdade.
- Como verificar: existindo dois contatos da mesma empresa com e-mail (ou telefone) equivalente, abrir a ficha de um deles apresenta o outro como sugestão de mesclagem.
- Aceite (H1): Dado dois contatos da mesma empresa com um dado de contato equivalente, Quando a ficha de um deles carrega, Então o outro aparece como sugestão real de mesclagem, E contatos sem equivalência não geram sugestão falsa.
- Prioridade: baixa. RFs: RF-UX-001. Descoberto no QA da fatia {AUD-12} (2026-07-12).
- Sintoma: (1) Dashboard, tabela "Relatório por Origem" com cabeçalhos em inglês (TOTAL LEADS, TOTAL VALUE, OPEN, WON, LOST, ABANDONED, WIN %). (2) Portal da Agência, Regras de Pontuação, com "Lead Scoring", "Recalcular scores" e "Nenhuma regra global de scoring".
- O que fazer: traduzir os rótulos dessas duas telas para português (mesma classe do {AUD-12}, porém fora do módulo Configurações).
- Como verificar: percorrer o Dashboard e o portal da Agência (Regras de Pontuação); nenhum texto em inglês visível, salvo jargão consagrado e nomes técnicos de terceiros.
- Aceite (H1): Dado o Dashboard e o portal da Agência, Quando o usuário os percorre, Então todos os rótulos estão em português.
- Prioridade: baixa. RFs: RF-UX-001. Registrado no planejamento da fatia {AUD-12} (2026-07-12).
- Sintoma: as opções de "Tipo de Empresa" (Perfil da Empresa) são tipos jurídicos estrangeiros traduzidos (Sociedade Limitada, Sociedade Anônima, etc.), não os tipos brasileiros reais (MEI, EI, EIRELI, Ltda, S.A.).
- O que fazer: decisão de produto sobre a taxonomia brasileira e migração dos values já gravados em organizations.settings (o {AUD-12} só traduziu os rótulos, preservando os values internos em inglês).
- Como verificar: o seletor de Tipo de Empresa lista os tipos jurídicos brasileiros; organizações existentes continuam com o tipo correto após a migração.
- Aceite (H1): Dado o cadastro da empresa, Quando o usuário escolhe o Tipo de Empresa, Então as opções são os tipos jurídicos brasileiros, E nenhum dado existente é perdido na migração.
- Prioridade: média. RFs: RNF-005. Descoberto no QA da fatia {AUD-13} (2026-07-12).
- Sintoma: o filtro is_test do {AUD-13} cobre a listagem de Subcontas, mas outras telas do Super Admin ainda contam ou listam as empresas de teste, a saber os KPIs "Organizações" e "Orgs Ativas" do painel da agência, o seletor de organização de destino em Aplicar Snapshot, e a tabela de configuração de domínio e marca (Whitelabel).
- Causa provável: cada uma dessas telas faz o próprio fetch de organizations sem o filtro is_test, que hoje vive só na query da listagem de Subcontas.
- O que fazer: aplicar o mesmo critério de ocultar is_test por padrão (com opção de revelar quando fizer sentido) nas contagens e nos seletores dessas telas, reusando a coluna is_test já existente. Nenhuma delas quebra hoje; é alinhamento ao espírito do RNF-005.
- Como verificar: nos KPIs do painel da agência, no seletor de destino de snapshot e na tabela de whitelabel, as empresas de teste não aparecem nem são contadas por padrão; o tenant real aparece limpo.
- Aceite (H1): Dado o Super Admin operando o painel da agência, Quando consulta os KPIs de organizações, os seletores de organização e as configurações, Então as empresas de teste não são contadas nem listadas por padrão, E o tenant real aparece corretamente.
- Prioridade: média. RFs: RNF-004, RF-CONV-054. Branch: fix/AUD-27-roteamento-api-morto.
- Sintoma: o Nginx reescreve /api/(.*) removendo o prefixo antes de a requisição chegar ao servidor de integrações, mas vários handlers só reconhecem o caminho COM /api/, então ficam inalcançáveis pela URL pública (404). Alguns têm tela que depende deles e está quebrada: salvar configuração de e-mail e salvar configuração de SMS. Outros afetados: criar evento no Google Calendar, reprocessar nomes de contatos do Meta, workflow de formulário do Meta Leads, e quatro leituras de relatório (Google Analytics, Meta Ads, Google Meu Negócio, formulários do Meta Leads).
- Causa provável: divergência entre o caminho pós-reescrita do Nginx e a string literal casada em cada handler; o padrão dominante no arquivo é casar os dois caminhos (com e sem /api/), mas esses handlers ficaram só com um.
- O que fazer: religar cada rota casando também o caminho sem /api/ (dual-match, o padrão do arquivo) e, ao religar, ADICIONAR em cada uma o mesmo guardião de autenticação e acesso à empresa do {AUD-26} (hoje inexploráveis por estarem mortas, mas são da mesma classe de risco). Confirmar quais têm caller real no front antes de expor.
- Como verificar: cada rota religada responde pela URL pública (não mais 404); salvar configuração de e-mail e de SMS volta a funcionar na tela; sem token a rota recusa com 401 e usuário de outra empresa com 403.
- Aceite (H1): Dado um handler de servidor que hoje só casa o caminho com /api/, Quando religado, Então responde pela URL pública com o mesmo guardião de autenticação do {AUD-26}, E as telas que dependem dele (salvar configuração de e-mail e de SMS) voltam a funcionar.
- Prioridade: média. RFs: RF-PERM-001. Branch: fix/AUD-29-reforcar-permissoes-papel-banco.
- Sintoma: nenhum visível na interface; achado de code review da fatia {AUD-19}: o controle que esconde botões conforme o papel do usuário roda só no frontend, e as políticas de acesso do banco nas tabelas de gestão (contatos, oportunidades e afins) validam apenas a organização do usuário, nunca a permissão do papel dele.
- Causa provável: a autorização por papel customizado existe só do lado do cliente. Um membro com papel restritivo (por exemplo, sem permissão de criar) que chame a API diretamente com o próprio token válido consegue inserir ou editar sem barreira real; o controle do frontend é cosmético para quem acessa a API direto.
- O que fazer: espelhar as permissões do papel também nas políticas de acesso do banco das tabelas de gestão relevantes (contatos, oportunidades, conversas, agendamento, automações, pagamentos), por meio de uma função auxiliar que resolve a permissão do papel do usuário na organização. Mesma classe de reforço do lado do servidor já aplicada nos cards de endurecimento anteriores.
- Como verificar: um membro com papel sem permissão de criar que chame a API direto (sem passar pela interface) é recusado pelo banco ao tentar inserir; papel com a permissão continua funcionando; dono, administrador e Super Admin não são afetados.
- Recorte do aceite (2026-07-14, feito antes de codar): o aceite abaixo dizia "uma ação" sem dizer quais, e requisito vago não reprova nada. Fica escopado às ações de escrita (criar, editar, excluir), que é exatamente o que o sintoma e o "Como verificar" deste card descrevem. Ver e exportar saíram para o {AUD-36}, porque reforçá-los no banco pela mesma técnica somaria a regra nova à regra de leitura pública do agendamento e derrubaria a página pública, além de fazer consultas com dados aninhados voltarem vazias em silêncio, trocando um defeito por outro.
- Nota de realidade (2026-07-14): este card endurece a metade-banco de uma funcionalidade cuja metade-produto não existe. Não há tela para criar nem atribuir papel (ver {AUD-37}), e em produção não há um único papel cadastrado nem um membro que não seja dono, então o risco corrigido aqui é real mas ainda dormente. Este card não entrega o RF-PERM-001.
- Aceite (H1): Dado um membro cujo papel nega uma ação de escrita (criar, editar ou excluir), Quando a requisição é feita por qualquer via (inclusive API direta), Então o banco recusa, E papéis com a permissão seguem funcionando, E dono, administrador e Super Admin não são afetados.
- Entregue em 2026-07-14 (merge b74e049, migration 089). O banco ganhou uma função de autorização que espelha, regra por regra, o mesmo controle que o frontend já usava para esconder botões, e ela passou a ser consultada por regras de escrita em nove tabelas de gestão (contatos, oportunidades, conversas, mensagens, agendamentos, calendários, automações, faturas e links de pagamento), cobrindo criar, editar e excluir. Nenhuma regra de isolamento por empresa que já existia foi alterada. Provado em produção por requisição real com token de um membro de verdade, não por leitura de código: com o papel negando criar, a gravação é recusada e nada entra; com o papel permitindo, a mesma requisição passa; quem é dono, administrador ou Super Admin não sentiu diferença; e quem não tem vínculo com a empresa continua barrado. O agendamento público e o formulário público não foram afetados, porque passam pelo servidor de integrações, que tem acesso próprio. Duas observações honestas: uma escrita recusada em editar ou excluir volta como "nada a fazer" em vez de erro (o dado fica protegido, que é o que o aceite exige, mas quem for ligar a tela de papéis no {AUD-37} não pode ler esse silêncio como sucesso); e o reforço só alcança os módulos que existem no catálogo do produto, então formulários, produtos e tarefas seguem sem regra de papel, o que depende do {AUD-38} e do {AUD-37} para fechar.
- Prioridade: alta. RFs: RF-LEAD-002. Descoberto no teste de não regressão da fatia {AUD-22} (2026-07-13).
- Sintoma: clicar em "Mesclar" em qualquer contato retornava erro 500; a mesclagem nunca acontecia (funcionalidade 100% quebrada desde cerca de maio, descoberta no teste de não regressão do {AUD-22}).
- Causa provável: o serviço do webhook chamava a função de mesclagem do banco com uma conexão de serviço que não carregava a identidade do usuário, então a checagem de "usuário autenticado" da função sempre falhava. Além disso, quando o Super Admin operava entrando como a empresa, a marca de "entrar como empresa" não chegava até essa chamada (só ia no canal principal, não no canal do webhook).
- O que fazer: a chamada de mesclagem passou a propagar a identidade do usuário (e a marca de entrar como empresa quando existe) até a função do banco; a validação de posse por organização voltou a funcionar de verdade.
- Como verificar: mesclar dois contatos duplicados conclui com sucesso, tanto como membro da empresa quanto como Super Admin entrando na empresa; o contato absorvido fica marcado como mesclado.
- Aceite (H1): Dado dois contatos duplicados, Quando o operador confirma a mesclagem por qualquer papel legítimo, Então a mesclagem conclui e o histórico fica unificado.
- Prioridade: média. RFs: a confirmar no DRS (área de automações / trigger links). Descoberto na entrega do {AUD-30} (2026-07-13).
- Sintoma: os três endpoints de trigger links do webhook (criar, listar, apagar) quebram ao serem chamados (erro 500), independente do resto.
- Causa provável: o código desses endpoints referencia nomes de variáveis de configuração que não existem no arquivo (grafia divergente das reais), então lança erro de referência antes de qualquer lógica.
- O que fazer: apontar para as variáveis reais de URL e chave pública (as mesmas usadas na correção do {AUD-30}) e testar os três endpoints.
- Como verificar: chamar os três endpoints de trigger links com dados válidos não gera erro de configuração.
- Aceite (H1): Dado uma requisição válida a qualquer um dos três endpoints de trigger links, Quando processada, Então responde sem erro de configuração.
- Entregue em 2026-07-15 (commit e303e18). Os três endereços liam duas variáveis de configuração que nunca existiram no arquivo, então estouravam antes de qualquer lógica e devolviam erro em toda chamada autenticada. Dito sem maquiagem: não é regressão, nasceram assim e nunca funcionaram em produção desde que foram escritos. A correção são três nomes de variável. Provado por requisição real, com o caso positivo e o negativo: antes, erro de configuração em toda chamada autenticada; depois, criar devolve o link com o endereço curto montado, listar devolve a lista, apagar apaga de verdade (conferido no banco, não só na resposta) e o link some da lista; sem autenticação continua recusando como antes; e o endereço curto redireciona e conta o clique. E provado também pela tela, por clique real de mouse na aba de Links Rastreáveis em Conversas: criar, listar, abrir o link curto, ver o contador subir de zero para um e apagar, nos temas claro e escuro, sem quebrar as telas vizinhas. Tudo em empresa de teste; a empresa cliente não foi tocada. Duas ressalvas honestas: as imagens da validação não puderam ser salvas em arquivo (limitação do ambiente, a evidência ficou só no registro da sessão), e o celular foi conferido por uma moldura de 390 pontos dentro da própria sessão, que é aproximação e não um aparelho real. Decisão de escopo registrada: não se encaminhou aqui a marca de entrar como empresa, porque a função que cria o link resolve a empresa por conta própria e ignoraria a marca, enquanto listar e apagar a honram, o que faria o Super Admin criar um link que sumiria da própria lista; isso é o {AUD-32}.
- Prioridade: média. RFs: RF-AGY (acesso transversal da operação com isolamento). Descoberto na entrega do {AUD-30} (2026-07-13).
- Sintoma: quando o Super Admin entra como uma empresa, as ações que passam pelo canal /api do webhook (fora o fluxo de mesclagem, já corrigido) podem não respeitar a empresa escolhida, porque a marca de entrar como empresa só era injetada no canal principal e no fluxo de mesclagem.
- Causa provável: a injeção da marca "entrar como empresa" nas chamadas ao webhook foi feita só no fluxo de mesclagem; os demais pontos que chamam /api diretamente ainda não usam o auxiliar já disponível.
- O que fazer: auditar os pontos do frontend que chamam /api do webhook e injetar a marca de entrar como empresa via o auxiliar já pronto (getImpersonatingOrgId); do lado do servidor, encaminhar a marca onde as chamadas usam a identidade do usuário.
- Como verificar: com o Super Admin entrando como uma empresa, qualquer ação que passa pelo canal /api reflete a empresa escolhida, não a empresa própria do Super Admin.
- Aceite (H1): Dado o Super Admin entrando como uma empresa, Quando usa qualquer ação que passa pelo canal /api, Então a ação respeita a empresa escolhida.
- Ampliação de escopo apurada no plano do {AUD-31} (2026-07-15): encaminhar a marca de entrar como empresa NÃO basta, e em alguns pontos sozinha piora. Onde a ação passa por função do banco que resolve a empresa por conta própria, a marca é ignorada e o par fica incoerente. Caso concreto e verificado: nos links rastreáveis, a função que cria o link resolve a empresa pelo vínculo de membro do usuário e ignoraria a marca, enquanto listar e apagar a honram pelo isolamento; encaminhar só o cabeçalho faria o Super Admin criar um link que sumiria da própria lista. Por isso este card precisa incluir as funções do banco que resolvem empresa sozinhas (a de criar link rastreável é uma delas), e não só o encaminhamento no frontend. Some-se a isso que essa mesma função escolhe a empresa com "a primeira que aparecer", sem critério de ordenação, o que é não determinístico para usuário com mais de uma empresa.
- Instância confirmada (2026-07-14, no qa do {AUD-34}): a listagem de Caixas de Email não enxerga nada quando o Super Admin está no modo entrar como empresa. A conta é criada, mas some da lista. A causa é a mesma deste card: a listagem descobre as empresas do usuário apenas pelo vínculo de membro, e o Super Admin não tem vínculo, então a lista volta vazia. As demais ações da mesma tela (criar, editar, excluir) funcionam porque usam a verificação que reconhece o Super Admin. O usuário real da empresa lista normalmente; quem fica cego é o operador da Modulareasy em modo suporte. Referência técnica para a correção: webhook-index.js:3529-3546 (a listagem) contra webhook-index.js:473-482 (a verificação que reconhece o Super Admin), e webhook-index.js:3290-3291, que já encaminha a marca de entrar como empresa no fluxo de mesclagem e é o padrão a generalizar.
- Entregue em 2026-07-17 (merge 1ec9c8d, migration 094). Auxiliar único no servidor que honra a marca somente quando quem chama é Super Admin (validando o formato), aplicado nos cinco pontos que resolviam a empresa pela identidade do usuário; ponto único de chamada no frontend injetando a marca em toda requisição autenticada (37 chamadas roteadas, 11 públicas intocadas de propósito); os três repasses de links rastreáveis encaminham a marca; e a função do banco que cria o link rastreável passou a honrar a marca e ficou determinística, quando antes escolhia uma empresa qualquer para usuário com mais de uma. Provado em produção com par positivo e negativo: a listagem de Caixas de Email deixou de vir vazia no modo, o link criado nasce na empresa escolhida e aparece na própria lista, membro comum forjando a marca não escala privilégio e quem não é membro nem Super Admin segue bloqueado. A validação ainda achou e a própria fatia corrigiu um defeito irmão do {AUD-27}: a rota de gerar código Pix de fatura exigia um prefixo que o servidor de borda remove, então estava morta para qualquer usuário desde que nasceu; agora responde e foi exercitada de ponta a ponta. Fronteira honesta: os dois endereços do canal alternativo de whatsapp seguem mortos para todos pelo defeito próprio do {AUD-96}, com o auxiliar de impersonate já aplicado neles, valendo quando aquele card os religar.
- Prioridade: média. RFs: RNF-005. Descoberto no QA da fatia {AUD-25} (2026-07-14).
- Sintoma: no painel da agência, os indicadores "Usuários" e "Contatos" não refletem só o tenant real. "Usuários" conta todos os perfis da plataforma (inclui gente que só existe em empresas de teste); "Contatos" depende da empresa em que o Super Admin está no momento (mostra o número da empresa ativa, não o total real), então nunca exibe a contagem verdadeira do Hiit.
- Causa provável: diferente dos indicadores de organizações (já filtrados no {AUD-25}), as contagens de usuários e contatos não filtram empresas de teste; a de contatos ainda é lida no escopo da empresa ativa, em vez de um total agregado das empresas reais.
- O que fazer: fazer as contagens de "Usuários" e "Contatos" do painel da agência agregarem apenas as empresas não-teste, por um cálculo no servidor que respeite o isolamento (hoje ficam presas à empresa ativa). Reusa a marca is_test já existente nas empresas.
- Como verificar: no painel da agência, "Usuários" e "Contatos" refletem só as empresas reais (hoje só o Hiit), independentemente de qual empresa o Super Admin esteja consultando.
- Aceite (H1): Dado o Super Admin no painel da agência, Quando consulta os indicadores de Usuários e Contatos, Então eles contam apenas as empresas reais, E o valor não muda conforme a empresa ativa.
- Entregue em 2026-07-18 (merge eb2e875, migration 095). Os dois cards passaram a ler uma função agregada do banco (com definidor de segurança e gate de Super Admin) que soma apenas as empresas reais (marca de teste falsa): Usuários conta os membros distintos dessas empresas e Contatos conta os contatos delas, num único valor que não depende mais da empresa ativa. Provado em produção: os cards mostram 1 e 1503 (só a piloto é real), e a invariância foi exercitada entrando como duas empresas de teste diferentes e conferindo que os valores não se movem. Negativo pareado: a função recusa quem não é Super Admin. Os cinco indicadores que o {AUD-25} já filtrava seguem intactos. Achado adjacente, fora deste H1 e agora rastreado no {AUD-101}: os gráficos das abas SaaS e Atividade ainda contam empresas de teste.
- Prioridade: alta (era P0). RFs: área de Conversas, e-mail (a confirmar no DRS o RF exato de contas de e-mail).
- Sintoma: na tela Configurações, Caixas de Email, adicionar uma conta de e-mail nunca funcionava, o servidor recusava por falta de um campo obrigatório. Além disso, o interruptor "Pular teste de conexão" (restrito ao Super Admin) habilitava o botão Salvar, mas o clique não fazia nada, sem erro nem aviso.
- Causa provável: o front nunca incluía o identificador da empresa no envio, e o servidor exige; a trava do botão Salvar continuava exigindo teste de conexão bem sucedido, ignorando o próprio interruptor que a interface oferecia.
- O que fazer: injetar o identificador da empresa no ponto único onde a empresa ativa já era conhecida (vale para qualquer chamada); fazer a trava do salvar honrar o mesmo interruptor. O servidor já restringe o pular-teste ao Super Admin, o controle não afrouxou.
- Como verificar: adicionar uma conta de e-mail em Caixas de Email conclui com sucesso; com o interruptor de pular teste ligado (Super Admin), o Salvar grava de verdade.
- Aceite (H1): Dado um operador em Caixas de Email, Quando adiciona uma conta de e-mail, Então a conta é criada de fato, E o interruptor de pular teste de conexão do Super Admin salva de verdade.
- Estado: entregue e validado em produção (criação retorna sucesso onde antes recusava; o interruptor salva).
- Prioridade: máxima (segurança). RFs: RNF-001 (isolamento por empresa), RF de captura por formulário. Descoberto em 2026-07-14, no planejamento do {AUD-29}. Branch: fix/AUD-35-isolamento-formularios-campanhas.
- Sintoma: as tabelas de formulários e de campanhas têm as regras de isolamento escritas, mas a proteção que faz essas regras valerem está desligada nas duas, então elas nunca entraram em vigor. Provado em produção: uma requisição sem nenhum login, usando apenas a credencial pública que acompanha o site, devolveu o formulário cadastrado e a empresa dona dele; a mesma requisição contra a tabela de contatos, onde a proteção está ligada, devolve vazio, como deve ser.
- Causa provável: as tabelas foram criadas com as regras de acesso mas sem ligar a proteção que as ativa. Agrava o quadro que a credencial pública tem permissão não só de ler, mas de inserir, alterar, apagar e esvaziar as duas tabelas, para todas as empresas.
- O que fazer: ligar a proteção de isolamento nas duas tabelas e reduzir o alcance da credencial pública ao mínimo, sem quebrar a captura pública de leads: a página pública de formulário precisa continuar lendo a definição do formulário para renderizar e continuar recebendo envio. Seguir o padrão que o próprio produto já usa na página pública de agendamento (uma regra de leitura pública restrita ao que está publicado, convivendo com a regra por empresa) em vez de inventar mecanismo novo. Varrer o banco atrás de outras tabelas que tenham dono de empresa e a proteção desligada, e corrigir todas no mesmo movimento, porque é o mesmo defeito de raiz.
- Como verificar: sem login, a credencial pública não devolve mais formulário nem campanha de nenhuma empresa; a página pública de formulário continua abrindo e recebendo envio de ponta a ponta; um membro continua vendo e gerenciando os formulários da própria empresa e não alcança os de outra; o Super Admin no modo entrar como empresa continua funcionando.
- Aceite (H1): Dado alguém sem login, de posse apenas da credencial pública do site, Quando pede formulários ou campanhas, Então não recebe registro de nenhuma empresa, E a página pública de formulário continua renderizando e recebendo envio, E o membro continua gerenciando os formulários da própria empresa.
- Prioridade: média. RFs: RF-PERM-001. Recorte explícito do {AUD-29}, feito em 2026-07-14.
- Sintoma: nenhum visível hoje. O {AUD-29} reforça no banco as permissões de escrita do papel (criar, editar, excluir), mas ver e exportar continuam valendo só no frontend: um membro cujo papel nega ver um módulo ainda consegue ler os dados daquele módulo chamando a API direto com o próprio token.
- Causa provável: a técnica do {AUD-29} (uma regra restritiva somada às que já existem) não serve para leitura sem efeito colateral. Aplicada à leitura, ela se soma também à regra de leitura pública do agendamento e derruba a página pública, e faz consultas que trazem dados aninhados voltarem vazias em silêncio em vez de recusarem com erro. Precisa de mecanismo próprio.
- O que fazer: decidir e implementar o reforço de ver e exportar, avaliando se o lugar certo é o banco (com regra de leitura por módulo que conviva com as leituras públicas legítimas) ou a camada de serviço. Depende do {AUD-37} para ser exercitável de verdade, já que hoje não existe caminho pela interface para criar um papel.
- Como verificar: um membro cujo papel nega ver um módulo não obtém os dados daquele módulo por nenhuma via, inclusive API direta; as páginas públicas de agendamento e de formulário continuam funcionando; consultas com dados aninhados não voltam vazias em silêncio.
- Aceite (H1): Dado um membro cujo papel nega ver um módulo, Quando pede os dados desse módulo por qualquer via, Então não os recebe, E as páginas públicas seguem funcionando, E nenhuma consulta legítima passa a voltar vazia em silêncio.
- Entregue em 2026-07-18 (merge 151fef5, migration 099). O reforço passou para o banco: quinze regras restritivas de leitura, uma por tabela, exigem que o papel libere ver o módulo, nas mesmas quinze tabelas do mapa de escrita do {AUD-29} e do {AUD-38b} (a de atividades com guarda que só cobra o papel quando o registro é do tipo tarefa). Os dois medos do card foram refutados por medição, não por leitura de código: as páginas públicas leem por um caminho de servidor com acesso próprio, imune a regra que vale para usuário autenticado, então não caem; e os encaixes que trazem dados de outro módulo foram mapeados, a linha-mãe sobrevive com o campo aninhado em branco, sem consulta legítima voltando vazia por inteiro em silêncio. Recorte declarado: exportar não tem endereço de servidor próprio e colapsa em ver no banco, então o par ver-liberado com exportar-negado segue valendo só na tela, front-only. Decisão do planejamento: reforço no banco, com token de servidor imune por vir do caminho de serviço. Provado por qa com acesso de membro de papel restritivo de verdade: zero linhas em contatos, oportunidades e conversas onde existiam dezenove, dois e dez; dono, administrador, membro sem papel e Super Admin intactos, inclusive no modo entrar como empresa; agendamento, horários e formulário públicos respondendo; e a guarda de atividades protege a linha do tempo. Gates plan APPROVED, qa PASS, review APPROVED (as chaves de módulo batem uma a uma com o catálogo canônico). Smoke visual real nos temas claro e escuro e no aparelho móvel, com telas de dados.
- Prioridade: alta. RFs: RF-PERM-001 (Essencial). Descoberto em 2026-07-14, no planejamento do {AUD-29}.
- Sintoma: não existe tela de Papéis e Permissões no produto. O administrador não tem como criar um papel, marcar o que ele pode fazer, nem atribuí-lo a um membro. Em produção não há nenhum papel cadastrado e nenhum membro com papel atribuído: todos os seis membros são donos, e dono passa por cima de qualquer permissão.
- Causa provável: a fundação foi construída e a interface não. A tabela de papéis, o vínculo do membro com o papel e o controle que esconde botões conforme a permissão existem; as funções de front que criam, editam, apagam e atribuem papel também existem, mas nenhuma tela as chama, então são código morto.
- O que fazer: construir a tela de Papéis e Permissões (lista de módulos com um liga e desliga por módulo e marcações de ver, editar, excluir e exportar) e a atribuição de papel na tela de Membros, aproveitando as funções de front que já existem. Antes de construir, fechar o catálogo de módulos e ações com o {AUD-38}, para não erguer a tela sobre chaves divergentes.
- Como verificar: um administrador cria um papel restritivo pela interface, atribui a um membro, e o membro passa a enxergar e poder somente o que foi liberado; o reforço de escrita do {AUD-29} passa a ser exercitável pela interface, sem depender de comando direto no banco.
- Aceite (H1): Dado que sou administrador, Quando abro Papéis e Permissões, crio um papel marcando o que ele pode e atribuo a um membro, Então o membro passa a operar somente dentro do que foi liberado, E o banco recusa o que o papel nega.
- Prioridade: média. RFs: RF-PERM-001. Descoberto em 2026-07-14, no planejamento do {AUD-29}.
- Sintoma: latente hoje (todos os usuários são donos, e dono passa por cima de qualquer permissão), vira defeito real no primeiro papel restritivo que existir. Várias telas perguntam ao controle de permissão por um módulo que não está no catálogo, ou pelo módulo de outra entidade: Campanhas pergunta por um módulo "campanhas" e por uma ação "enviar" que não existem; Produtos, Tarefas e Formulários perguntam pela permissão de Contatos; Relatórios pergunta pela permissão de Configurações; Caixas de Email pergunta por criar e excluir em Configurações, que só prevê ver e editar. A divergência de Automações, que era da mesma família, foi dada como corrigida junto com o {AUD-29}, mas seguia viva no código e só foi corrigida na entrega do {AUD-38} (2026-07-18).
- Causa provável: as telas foram escritas em momentos diferentes sem um catálogo único de módulos e ações. Quando o módulo perguntado não existe, o controle responde liberando apenas ver, então a ação fica negada para sempre, para qualquer papel, inclusive um que a liberasse.
- O que fazer: fechar o catálogo canônico de módulos e ações (o mesmo que a tela do {AUD-37} vai listar e o mesmo que o banco reforça no {AUD-29}), fazer cada tela perguntar pelo módulo da própria entidade, e decidir no DRS quais entidades merecem módulo próprio (Produtos, Tarefas, Formulários, Campanhas, Relatórios) em vez de pegarem carona no de Contatos. Atualizar o RF-PERM-001 com a lista final antes de codar.
- Como verificar: nenhuma tela consulta módulo ou ação fora do catálogo; um papel que libera criar em cada módulo consegue criar naquela tela; um papel que nega não consegue.
- Aceite (H1): Dado um papel que libera criar num módulo, Quando o usuário abre a tela daquele módulo, Então consegue criar, E nenhuma tela consulta módulo ou ação fora do catálogo.
- Entregue em 2026-07-18 (merge 3670d2f). O catálogo canônico virou fonte única no código (13 módulos com as ações por módulo, o mesmo que o RF-PERM-001 republicado fixa) e as sete telas divergentes passaram a perguntar pelo módulo da própria entidade: Tarefas, Produtos e Formulários deixaram a carona de Contatos, Automações deixou de pedir um módulo inexistente, Relatórios ganhou módulo próprio, Campanhas entrou no catálogo com a ação de enviar, e Caixas de Email passou a exigir editar Configurações. Provado por qa com membro de papel restritivo de verdade: criar liberado funciona pela tela (tarefa e produto criados por clique e conferidos no banco), criar negado some da tela e o banco recusa o bypass por API direta onde há reforço; dono e administrador sem mudança nenhuma. O qa ainda provou ao vivo que as tabelas de Tarefas, Produtos, Formulários e Campanhas não têm o reforço de escrita no banco (virou o {AUD-38b}) e que botões de estado vazio ignoram a permissão (virou o {AUD-102}).
- Prioridade: alta. RFs: RF-PERM-001. Família {AUD-29}/{AUD-38}. Descoberto em 2026-07-18, no qa do {AUD-38}, por teste ao vivo.
- Sintoma: um membro cujo papel nega excluir apagou uma tarefa de verdade por chamada direta de API com o próprio token. As tabelas de Tarefas, Produtos, Formulários e Campanhas só têm isolamento por empresa, sem consultar a função de autorização por papel: o papel vale na tela e não vale no banco.
- Causa provável: a migration do {AUD-29} cobriu as nove tabelas dos seis módulos que existiam no catálogo da época; os módulos que entraram no catálogo canônico do {AUD-38} ficaram sem o reforço.
- O que fazer: migration nova estendendo as regras restritivas de escrita (criar, editar, excluir consultando a função de autorização) às tabelas de Tarefas, Produtos, Formulários e Campanhas, com backup antes e o mesmo rito da migration do {AUD-29}.
- Como verificar: par positivo e negativo com membro de papel restritivo na empresa de teste: o que o papel nega é recusado pelo banco por API direta e a linha permanece; o que o papel libera passa; dono, administrador e Super Admin sem mudança; páginas públicas intocadas.
- Aceite (H1): Dado um membro cujo papel nega excluir tarefas, Quando tenta excluir por chamada direta de API, Então o banco recusa e a linha permanece, E o mesmo reforço vale para criar e editar em Produtos, Formulários e Campanhas.
- Prioridade: média. RFs: RF-PERM-001. Família {AUD-29}/{AUD-38}/{AUD-38b}. Descoberto em 2026-07-18, no planejamento do {AUD-38b}, por inventário do catálogo de políticas do banco ao vivo.
- Sintoma: além das seis tabelas fechadas pelo {AUD-38b}, sobram tabelas de escrita dos mesmos módulos do catálogo (Contatos, Oportunidades, Calendário, Automação, Pagamentos, Campanhas) que só têm isolamento por empresa e não consultam a função de autorização por papel. Um membro cujo papel nega criar, editar ou excluir consegue escrever nelas por chamada direta de API com o próprio token. O papel vale na tela e não vale no banco.
- Causa provável: a migration do {AUD-29} e a migration 097 do {AUD-38b} fecharam a lista curada das entidades principais de cada módulo; as entidades acessórias (arquivos e identificadores de contato, etiquetas, listas inteligentes, regras de pontuação, funis, pedidos, modelos de mensagem), as junções sem coluna de empresa (contato x etiqueta, contato x empresa, etapas de funil, produtos da oportunidade, membros do calendário, regras e exceções de disponibilidade) e as tabelas filhas dos fluxos de automação ficaram de fora do reforço.
- O que fazer: estender as regras restritivas de escrita a essas tabelas, uma a uma. Antes de gatear cada tabela, verificar se existe caminho legítimo de servidor ou público que escreve nela (captura pública de formulário, sincronização, worker de serviço), porque técnica de escrita não se copia cega para caminhos com entrada pública ou de servidor (lição do {AUD-36}). As junções sem coluna de empresa precisam gatear pela entidade-pai. Backup antes e o mesmo rito da migration do {AUD-29}.
- Contagem:
- Universo: 69 tabelas com política de escrita alcançáveis por um membro logado (73 no total com política de escrita, menos 4 exclusivas de servidor). Contado pelo catálogo de políticas do banco ao vivo em 2026-07-18, não por busca de texto no código.
- Critério (comportamental): a tabela aceita criar, editar ou excluir por chamada direta de API com o token do próprio membro, sem consultar a função de autorização por papel.
- Placar: 69 alcançáveis = 10 já reforçadas (9 da migration do {AUD-29} mais a de papéis do {AUD-37}) + 6 fechadas pelo {AUD-38b} (migration 097) + 53 ainda sem reforço. Fecha: 10 + 6 + 53 = 69.
- Recorte deste card: as tabelas do balde dos escapes de mesmo módulo dentro das 53. A lista é nominal, herdada do gate de planejamento do {AUD-38b}, não é uma varredura nova; o número exato dentro das 53 depende de resolver, por tabela, os itens abertos do "O que fazer" (quais tabelas filhas de fluxos e quais objetos de disponibilidade qualificam).
- Lado negativo (lido por inteiro): empresas e etiquetas, ambas com política de escrita alcançável por membro autenticado no catálogo ao vivo e sem regra restritiva por papel, aceitam escrita por API direta hoje.
- Amostra de um tenant? Não. A contagem vem do catálogo de políticas do banco, que é estrutural e vale para toda empresa, não de uma amostra de dados de um tenant.
- Evidência: 2026-07-18, catálogo de políticas ao vivo, posterior à migration 097 (entregue em produção no merge f6b3bfd). O gap é o que a 097 deixou de fora de propósito, não algo já corrigido.
- Reprova por: RF-PERM-001. H1 literal: "E o banco recusa o que o papel nega". Notas do RF: violado quando "um membro cujo papel nega uma ação a executa por qualquer via". Escrita por API direta numa tabela de módulo do catálogo é exatamente essa via.
- Como verificar: par positivo e negativo com membro de papel restritivo na empresa de teste, por tabela: o que o papel nega é recusado pelo banco por API direta e a linha permanece; o que o papel libera passa; dono, administrador e Super Admin sem mudança; os caminhos públicos e de servidor (captura de formulário, sincronização, workers) seguem escrevendo.
- Aceite (H1): Dado um membro cujo papel nega criar, editar ou excluir num módulo, Quando tenta escrever por chamada direta de API numa tabela desse módulo listada aqui, Então o banco recusa e a linha permanece, E os caminhos legítimos de servidor e público continuam escrevendo.
- Prioridade: média. RFs: RF-PERM-001. Família {AUD-29}/{AUD-38}/{AUD-38b}. Descoberto em 2026-07-18, no planejamento do {AUD-38b}, por inventário do catálogo de políticas do banco ao vivo.
- Sintoma: as tabelas dos módulos Configurações e Administração (campos personalizados, contas de e-mail, integrações, SMS, WhatsApp, assinaturas de leads da Meta, chaves de API de saída, assinaturas de saída, snapshots e aplicações de snapshot, membros da empresa) só têm isolamento por empresa e não consultam a função de autorização por papel. Um membro cujo papel nega ver ou editar Configurações ou Administração consegue escrever nelas por API direta com o próprio token.
- Causa provável: esses módulos têm semântica de ver e editar própria (não o criar, editar, excluir dos módulos operacionais), e por isso ficaram fora tanto da lista curada do {AUD-29} quanto do recorte de escrita do {AUD-38b}.
- O que fazer: gatear cada tabela pela ação certa do módulo dela no catálogo (Configurações ver e editar, Administração ver e editar), uma a uma. Antes de gatear, verificar por tabela se existe caminho legítimo de servidor ou de sincronização que escreve nela (troca de token de OAuth, cache de sincronização, worker de saída), porque técnica de escrita não se copia cega para leitura nem para casos com caminho de servidor (lição do {AUD-36}). Membros da empresa já tiveram a regra de escrita endurecida pelo {AUD-103}; conferir se resta ação de escrita não coberta. Backup antes e o mesmo rito da migration do {AUD-29}.
- Contagem:
- Universo: 69 tabelas com política de escrita alcançáveis por um membro logado (73 no total com política de escrita, menos 4 exclusivas de servidor). Contado pelo catálogo de políticas do banco ao vivo em 2026-07-18, não por busca de texto no código.
- Critério (comportamental): a tabela aceita criar, editar ou excluir por chamada direta de API com o token do próprio membro, sem consultar a função de autorização por papel.
- Placar: 69 alcançáveis = 10 já reforçadas (9 da migration do {AUD-29} mais a de papéis do {AUD-37}) + 6 fechadas pelo {AUD-38b} (migration 097) + 53 ainda sem reforço. Fecha: 10 + 6 + 53 = 69.
- Recorte deste card: as tabelas do balde dos módulos de configuração e administração dentro das 53. A lista é nominal, herdada do gate de planejamento do {AUD-38b}, não é uma varredura nova.
- Lado negativo (lido por inteiro): integrações e chaves de API de saída, ambas com política de escrita alcançável por membro autenticado no catálogo ao vivo e sem regra restritiva por papel, aceitam escrita por API direta hoje.
- Amostra de um tenant? Não. A contagem vem do catálogo de políticas do banco, que é estrutural e vale para toda empresa, não de uma amostra de dados de um tenant.
- Evidência: 2026-07-18, catálogo de políticas ao vivo, posterior à migration 097 (entregue em produção no merge f6b3bfd). O gap é o que a 097 deixou de fora de propósito, não algo já corrigido.
- Reprova por: RF-PERM-001. H1 literal: "E o banco recusa o que o papel nega". Notas do RF: violado quando "um membro cujo papel nega uma ação a executa por qualquer via". O catálogo tem os módulos Configurações (ver, editar) e Administração (ver, editar), então escrita negada por API direta nessas tabelas é essa via.
- Como verificar: par positivo e negativo com membro de papel que nega editar Configurações e Administração na empresa de teste, por tabela: a escrita negada é recusada pelo banco por API direta e a linha permanece; quem tem a permissão passa; dono, administrador e Super Admin sem mudança; trocas de token, sincronizações e workers de saída seguem funcionando.
- Aceite (H1): Dado um membro cujo papel nega editar Configurações ou Administração, Quando tenta escrever por API direta numa tabela desses módulos listada aqui, Então o banco recusa e a linha permanece, E as trocas de token, sincronizações e workers de serviço continuam escrevendo.
- Entregue em 2026-07-19 (merge cd5efd2, migration 101). O reforço de escrita chegou aos módulos de Configurações e Administração: vinte e sete regras restritivas em nove tabelas, cada uma exigindo que o papel libere editar Configurações ou Administração, sem tocar nenhuma regra de isolamento por empresa que já existia (só nega, nunca concede). Recorte real reconciliado (drift D1): das onze tabelas nomeadas no título, nove foram gateadas e duas ficaram de fora por construção, snapshots e aplicações de snapshot, que não têm coluna de empresa (recurso do fornecedor, sem empresa dona, já restrito a Super Admin por regra própria); o recorte real do card é nove tabelas, não onze. Nota honesta sobre o alcance vivo (D2): das nove gateadas, quatro barram efeito exercitável hoje (campos personalizados, integrações, configurações de SMS e configurações de WhatsApp) e cinco são reforço defensivo, exaustivo por construção, porque já eram inertes por regras de dono e administrador que as cobriam (contas de e-mail, assinaturas de leads da Meta, chaves de API de saída, assinaturas de saída e membros da empresa, esta já endurecida pelo {AUD-103}); o H1 vivo era exercitável só nas quatro, e nas cinco o reforço fecha a porta por princípio. Provado por qa com token de membro de papel restritivo de verdade (JWT real, sem senha em navegador): a escrita negada é recusada célula a célula por API direta e a linha permanece; dono, editor e Super Admin passam nas vinte e quatro operações positivas; o token de serviço é imune por vir do caminho de servidor (troca de OAuth, sincronização de e-mail, worker de saída); fixtures limpas por lista nominal, Hiit intacta. Telas alinhadas com o gating de editar: campos personalizados, SMS e WhatsApp ganharam o desabilita quando o papel nega; integrações e contas de e-mail já gateavam. Gates plan APPROVED com notas, qa PASS, review APPROVED (vinte e sete de vinte e sete regras conferidas uma a uma ao vivo com o gate, INSERT só com verificação de gravação, UPDATE com as duas, DELETE só na leitura). Da medição nasceram dois cards: o {AUD-105} (a leitura de Configurações e Administração ainda não é reforçada por papel no banco) e o {AUD-106} (o padrão do membro sem papel deixa editar Administração liberado por omissão, ao contrário de Configurações).
- Prioridade: alta (segurança). RFs: RNF-001 (isolamento por empresa), RF de agendamento público. Descoberto em 2026-07-14, durante o {AUD-35}.
- Sintoma: a regra que libera a leitura pública dos calendários libera todo calendário ativo, de qualquer empresa, sem nenhum filtro de dono. Na prática, quem tem apenas a credencial pública do site consegue listar os calendários ativos de todas as empresas, com nome e empresa dona. Hoje existe um único calendário ativo, de uma empresa de teste, então nada de cliente está exposto neste momento, mas a regra é cega por construção e passa a vazar no instante em que o piloto publicar um calendário.
- Causa provável: a regra nasceu para sustentar a página pública de agendamento, que precisa ler o calendário que o visitante vai usar, e foi escrita larga demais (todo calendário ativo) em vez de estreita (o calendário específico que a página pede). Diferente do {AUD-35}, aqui a proteção está ligada: o problema é a regra em si. A varredura feita no {AUD-35} mostrou que os calendários são o único caso: as demais tabelas com regra pública cega (planos, configurações públicas e modelos de automação) não pertencem a nenhuma empresa, são globais, então nelas a regra larga é por desenho.
- O que fazer: a evidência levantada em 2026-07-14 aponta que a regra virou código morto e que o certo é removê-la, não estreitá-la. O {AUD-03} moveu as consultas públicas de agendamento do navegador para o servidor, e hoje as únicas leituras da tabela de calendários pelo navegador estão na área logada, já filtradas pela empresa do usuário; a página pública de agendamento não lê a tabela direto. Confirmar isso de forma definitiva (inclusive os fluxos públicos de reagendar e de cancelar por link) e então remover a regra. Se aparecer alguma leitura pública direta que ainda dependa dela, aí sim estreitar ao calendário pedido em vez de liberar a lista inteira.
- Item secundário, mesma família, severidade baixa: a regra de leitura da biblioteca de modelos de automação libera tudo para qualquer um, sem exigir sequer login, e sem distinguir modelo publicado de rascunho. Hoje não há rascunho e os cinco modelos são da própria operação, sem dado de cliente, por isso não vaza nada agora. Mas o {AUD-06} restringiu a listagem de rascunhos ao Super Admin apenas na interface, então o primeiro rascunho criado fica legível por fora dela. Estreitar a regra para acompanhar o que a interface promete.
- Como verificar: com apenas a credencial pública do site, não é possível listar calendários de empresas às quais não se pertence; a página pública de agendamento continua abrindo, mostrando horários e concluindo um agendamento de ponta a ponta; um rascunho de modelo de automação não é legível sem login.
- Aceite (H1): Dado alguém sem login, de posse apenas da credencial pública do site, Quando pede a lista de calendários, Então não recebe calendário de nenhuma empresa, E a página pública de agendamento continua funcionando de ponta a ponta, E um rascunho de modelo de automação não é legível sem login.
- Prioridade: média. RFs: RF-AGY (acesso transversal da operação com isolamento). Descoberto no teste do {AUD-35} (2026-07-14).
- Sintoma: quando o Super Admin sai do modo entrar como empresa, a escolha da empresa continua guardada no navegador. Ao navegar direto por endereço depois de ter saído, o sistema volta a assumir a empresa antiga e o modo se restabelece sozinho, sem ninguém pedir. Não é falha de isolamento (a permissão continua sendo conferida e a empresa precisa existir), é o botão de sair que não desfaz o que promete.
- Causa provável: a saída limpa o estado da tela mas não apaga a marca da empresa ativa guardada no navegador; ao recarregar, a rotina que restaura o perfil lê essa marca e reconstitui o modo por conta própria.
- O que fazer: fazer a saída apagar também a marca guardada no navegador, no mesmo ponto onde ela é gravada na entrada, para entrada e saída serem simétricas.
- Como verificar: o Super Admin entra numa empresa, sai, navega direto por endereço, e o sistema não volta ao modo entrar como empresa; entrar de novo continua funcionando normalmente.
- Aceite (H1): Dado o Super Admin que saiu do modo entrar como empresa, Quando navega direto por endereço, Então o sistema não restabelece o modo sozinho, E entrar de novo continua funcionando.
- Prioridade: média. RFs: RNF-001 (isolamento por empresa), RF-AGY (painel de status das subcontas). Descoberto em 2026-07-14, na validação do {AUD-29}.
- Sintoma: toda vez que um usuário é criado no sistema de login, uma empresa nova é criada junto, com o nome tirado do e-mail, e o usuário vira dono dela. Se esse usuário é excluído depois, o vínculo dele some mas a empresa fica, sem nenhum membro, e como não está marcada como empresa de teste, ela passa a ser contada e listada como cliente real no painel do Super Admin. Em 2026-07-14 sobraram três empresas assim (duas de nome "aud29-probe" e uma "qa-aud29-multitab"), todas sem membro e sem nenhum dado, criadas por usuários de validação que já foram removidos.
- Causa provável: existe um gatilho no banco que, a cada usuário criado, cria perfil, cria uma empresa e dá a posse dela ao usuário. É comportamento de produto de auto-atendimento, onde quem se cadastra ganha o próprio espaço; mas este produto é um painel interno em que a operação da Modulareasy provisiona as subcontas, e cadastro por auto-atendimento está fora do escopo. A exclusão do usuário remove o vínculo em cascata e não tem nada que remova ou marque a empresa que sobrou.
- O que fazer: decidir primeiro a regra de produto, porque ela muda o conserto: se nenhum usuário deve ganhar empresa automaticamente, o provisionamento sai do gatilho e passa a ser explícito (é o que já acontece hoje pelo assistente de criação de empresa); se deve continuar existindo para algum caminho, a empresa criada assim precisa nascer marcada de forma que não seja contada como cliente real, e a exclusão do usuário precisa tratar a empresa que fica sem dono. Vale conferir de passagem o convite de membro: se convidar alguém para uma empresa existente também cria uma empresa paralela para essa pessoa, o efeito é pior que sujeira de painel.
- Como verificar: criar um usuário pelo caminho normal do produto não faz surgir empresa nenhuma no painel de Subcontas; excluir um usuário não deixa empresa sem dono para trás; e as três empresas órfãs de 2026-07-14 não aparecem mais entre os clientes reais.
- Nota de limpeza (2026-07-14, resolvida): as três empresas órfãs foram excluídas por decisão do Wladimir, por lista nominal e com verificação de que continuavam vazias no instante da exclusão (nenhum usuário, nenhum contato, nenhuma oportunidade). Depois disso a única empresa marcada como cliente real é a Hiit Fitwear, o tenant piloto, com os 1.503 contatos dela intactos.
- Entregue em 2026-07-22 (migration 103, merge 83cc7a0). A regra de produto foi decidida: nenhum usuário ganha empresa automaticamente. O gatilho do banco que criava perfil, empresa e posse a cada usuário novo passou a criar só o perfil; o provisionamento de empresa ficou explícito, pelo assistente do Super Admin, como já era o caminho oficial. O comentário do convite de membro foi corrigido para não prometer o que o código não faz. Provado por qa (PASS) e review (APPROVED): criar um usuário pelo caminho normal não faz surgir empresa nenhuma no painel de Subcontas, e o painel segue mostrando só a Hiit Fitwear como cliente real, sem tela branca.
- Aceite (H1): Dado um usuário criado ou excluído por qualquer caminho, Quando olho o painel de Subcontas, Então não existe empresa criada sozinha nem empresa sem dono sendo contada como cliente real. Cumprido em 2026-07-22.
- Prioridade: alta. RFs: RF-INT (integrações), RF-LEAD (captura Meta Lead Ads), RNF-003 (confiabilidade). Descoberto em 2026-07-14, por desconfiança do Wladimir ("o sistema precisa fazer isso sozinho; outras ferramentas não ficam pedindo isso toda hora"). Ele estava certo.
- Sintoma: a tela diz que a conta Meta está conectada, e o acesso está morto. Em 2026-07-14 as duas conexões Meta cadastradas estavam com o acesso vencido havia 4 e 10 dias, ambas ainda exibidas como "conectada". Enquanto isso ninguém é avisado, e a captura de leads simplesmente não acontece.
- Causa (provada, não suposta): existe uma rotina que renova acessos automaticamente, agendada de 6 em 6 horas, e ela nunca tocou na Meta uma única vez. A rotina só olha conexões que têm um "cupom de renovação" (o mecanismo do Google). A Meta não usa cupom (renova apresentando o próprio acesso atual), e por isso a conexão da Meta é gravada sem cupom, de propósito. Resultado: o filtro exclui toda conexão Meta, e o trecho de código que sabe renovar a Meta nunca roda. Foi construído para funcionar sozinho e nunca funcionou.
- Agravantes na mesma família: (a) a rotina só age quando falta 5 minutos para vencer, o que é uma janela absurda para um acesso que dura 60 dias, e se o servidor estiver fora nessa janela perde-se o ciclo; (b) acesso já vencido não pode ser renovado, então o conserto do filtro sozinho não ressuscita as conexões atuais nem impede que uma falha de algumas horas vire trabalho manual; (c) a conexão continua marcada como "conectada" depois de vencida, que é a mesma doença de tela que finge sucesso que a Onda AUD vem corrigindo.
- O que fazer: o modelo foi decidido, é a Opção A (acesso de "usuário de sistema" do Gerenciador de Negócios da Meta, que não expira, o que ferramentas maduras fazem), e a parte manual dela já foi executada. FEITO (2026-07-22, com o Wladimir conduzindo o login): criado o usuário de sistema no portfólio da Modulareasy, gerado um acesso permanente e sem validade com as nove permissões da integração, a página da Modulareasy atribuída com controle total, e a página da Hiit Fitwear compartilhada como parceira (a atribuição por identificação da empresa falhava com um erro genérico da Meta; a atribuição por link de compartilhamento funcionou) e vinculada ao usuário de sistema com acesso parcial de parceiro (mensagens, anúncios e análises, sem o gerenciar de dono). As duas conexões da tabela de integrações foram religadas com o acesso novo, cifrado em repouso, validade sem fim, cache de acesso de página limpo, e provadas de ponta a ponta (o registro no banco, a decifra no serviço e a Meta respondendo pelas duas páginas). A tela que dizia "conectada" mentindo passou a dizer a verdade. RESTA (código, por isso o card segue aberto): a tela passar a mostrar "expirada" com o motivo quando uma conexão de fato morrer, em vez de continuar dizendo "conectada"; o painel de saúde acusar; e decidir o destino do renovador automático, que com um acesso que não expira ficou sem função (remover o código morto, ou reaproveitá-lo só para o Google, que ainda renova por cupom). Esse resto é a entrega de {C-MCRM-2} mais {C-MCRM-6}.
- Como verificar: uma conexão Meta chega perto do vencimento e é renovada sozinha, sem ninguém tocar; a data de validade avança nos registros; se a renovação falhar, a tela mostra "expirada" com o motivo e um caminho para religar, em vez de continuar dizendo "conectada"; e o painel de saúde acusa.
- Nota (atualizada 2026-07-22): a observação de 2026-07-14, de que as duas conexões estavam vencidas e sem volta, ficou superada. Elas foram religadas em 2026-07-22 com o acesso permanente da Opção A, que não expira, então não há mais o vencimento de 60 em 60 dias a temer para elas. A rotação do segredo do aplicativo segue pendente e está registrada em {C-MCRM-1}.
- Aceite (H1): Dado que a validade do acesso à Meta está próxima do fim, Quando a rotina automática roda, Então o acesso é renovado sem intervenção humana, E se a renovação falhar a conexão deixa de se declarar conectada e passa a exibir o motivo.
- Reconciliado em 2026-07-22 (council GO): o defeito de origem continua válido, mas a correção deixa de ser consertar o renovador e passa a ser a conexão permanente da Onda C-MCRM (ver {C-MCRM-2}), com a Opção A do council (acesso de usuário de sistema que não expira) adotada como mecanismo primário. Este card fica aberto e é resolvido pela entrega de {C-MCRM-2} mais {C-MCRM-6} (a saúde da conexão, que faz "conectada" significar conectada). A rotação pendente do segredo do aplicativo continua válida e entra em {C-MCRM-1}.
- Prioridade: alta. RFs: RF-AUTO-002 (Gatilhos, Alta), RF-CONV-014 (Links rastreáveis, Média). Descoberto na entrega do {AUD-31} (2026-07-15).
- Sintoma: o administrador monta uma automação, escolhe um gatilho na lista da tela (por exemplo "Tag adicionada", "Etapa alterada", "Oportunidade ganha" ou "Agendamento criado"), salva, a automação fica com status ativa e assim aparece na tela, e nunca roda. Nada avisa que aquele gatilho não existe de fato. É a mesma doença que a Onda AUD vem corrigindo: a tela finge sucesso.
- Evidência (reconciliada em 2026-07-15; a primeira versão deste card estava factualmente errada e foi refeita conferindo emissor por emissor): o editor oferece vinte gatilhos, não dezesseis, e onze têm emissor real, não quatro. Emitidos pelo servidor: novo contato, cliente respondeu, mensagem recebida, formulário enviado e limite de armazenamento atingido. Emitidos pela tela: tag adicionada, tag removida, etapa alterada, oportunidade ganha e oportunidade perdida. Emitido pelo coletor de e-mail: e-mail recebido. Ficam oito sem emissor nenhum: contato atualizado, status de conversa alterado, status de oportunidade alterado, agendamento criado, agendamento cancelado, lembrete de agendamento, fatura paga e fatura vencida.
- O vigésimo gatilho, execução manual, é caso à parte e não entra na conta dos mortos: por desenho nenhum fato o dispara, ele só roda quando outra automação o aciona pela ação de adicionar a workflow (e também quando um formulário de anúncio está mapeado para ele). Mas não existe botão de executar na tela, então o nome promete ao administrador uma execução manual que a interface não oferece: ou nasce o botão, ou o nome muda.
- Por que a primeira contagem errou (a lição vale para as próximas auditorias): duas afirmações da versão anterior eram falsas e uma delas escondia um defeito maior. Era falso que a tela não emitisse evento nenhum: ela emite seis, por dois pontos do código. Era falso que a função interna de eventos não fosse rota de servidor: ela é uma rota pública, e essa premissa falsa é justamente o que escondeu o {AUD-47}, o disparo sem autenticação achado depois. E cinco gatilhos que a tela emite passaram batidos porque escapam de busca por texto literal: as tags saem de um condicional e o ganho ou perda de oportunidade sai de um nome montado em tempo de execução. Contagem por busca literal não fecha esta conta; a conferência tem que ser emissor por emissor.
- Nota sobre e-mail recebido: tem emissor de verdade (o coletor de e-mail), por isso saiu da lista dos mortos, mas hoje é dormente por outro motivo, registrado no {AUD-50}: o agendador da coleta é recusado e a coleta nunca roda. Sem conta de e-mail cadastrada, ninguém sente.
- Risco hoje: real, mas dormente. Em produção existem três automações, todas com o gatilho de novo contato, que funciona; a empresa cliente Hiit Fitwear não tem automação nenhuma. Quem cai no buraco é o primeiro administrador que escolher qualquer um dos oito. Mesma natureza do risco dormente do {AUD-29}.
- Nota sobre o clique em link: o clique em link rastreável nem aparece na lista de gatilhos da tela, embora o RF-AUTO-002 o cite e o RF-CONV-014 o exija no aceite. Além disso o clique é gravado sem contato, porque a chamada que o registra passa o contato como nulo de forma fixa, e nenhuma tela lê a tabela de cliques. Ou seja, a segunda metade do RF-CONV-014 (o clique é registrado no histórico do contato e pode servir de gatilho) não existe, embora o {AUD-31} tenha devolvido a criação, a listagem e a exclusão dos links. O {AUD-31} não alegou o contrário: o aceite dele era só responder sem erro de configuração.
- Causa-raiz (o card não via isto; achada no planejamento de 2026-07-15, antes de qualquer código): não existe "a lista". Existem quatro listas de gatilhos no código, mantidas à mão e já divergentes entre si: a do menu de criar automação, a do menu do editor visual, o mapa de rótulos usado na lista de automações e um mapa de rótulos legados que só o editor enxerga. Uma delas ainda carrega um comentário prometendo estar "sincronizada" com a outra, promessa que nada garante e que já falhou. Enquanto a correção for "editar as listas", a lista nunca vai dizer a verdade por muito tempo: o próximo card reintroduz o drift. A correção é ter uma fonte só, e as telas derivarem dela.
- Prova de que já divergiram (dois defeitos vivos em produção, achados nesta análise): nove dos vinte gatilhos não têm rótulo no mapa da lista de automações, então uma automação com o gatilho de formulário enviado, que funciona, aparece na tela com o nome cru do evento em vez do nome legível; e o agendamento marcado tem dois nomes diferentes conforme a tela em que aparece.
- Não é dormente como o parágrafo de risco acima sugere, e esta é a correção mais importante do card: um dos modelos prontos de automação, o "Lembrete de agendamento", entrega uma automação quebrada em um clique. Ele usa justamente um dos gatilhos que nunca disparam, e o clique cria a automação já com esse gatilho. O produto sugere ao administrador uma automação que nunca vai rodar. E não é hipótese de laboratório: dois dos três workflows que existem em produção nasceram exatamente desses modelos, ou seja, o caminho do modelo é o caminho que as pessoas usam de fato.
- O que fazer: decidir gatilho por gatilho, não em bloco. Para cada um dos oito, ou passa a existir o emissor no ponto onde o fato acontece, ou o gatilho sai da lista enquanto não existir. Para a execução manual, ou nasce o botão de executar na tela, ou o nome deixa de prometer o que não existe. Não deixar a tela oferecer o que o produto não faz, e sem aviso explicando o defeito: a lista tem que dizer a verdade.
- Como verificar: para cada gatilho oferecido na tela, provocar o fato real no sistema (adicionar tag, mover etapa, ganhar oportunidade, criar agendamento) e confirmar que a automação ativa correspondente disparou e o contato foi inscrito.
- Aceite (H1): Dado um gatilho oferecido na lista do editor de automações, Quando o fato correspondente acontece para um contato, Então a automação ativa com aquele gatilho dispara e o contato é inscrito; E nenhum gatilho que não dispara é oferecido na lista.
- Prioridade: média. RFs: RF-CONV-014. Descoberto na revisão de código do {AUD-31} (2026-07-15).
- Sintoma: a rota que apaga link rastreável confere apenas se houve erro, não se alguma linha foi de fato afetada. Pedir a exclusão de um link de outra empresa não apaga nada (o isolamento protege, corretamente), mas a resposta é de sucesso. Quem chama recebe "apagado" para uma exclusão que não aconteceu.
- Causa: o handler responde sucesso fixo após a operação, sem checar o número de linhas afetadas. Mesma família do {AUD-42} e da doença que a Onda AUD vem corrigindo: dizer sucesso sem o fato ter ocorrido.
- Risco hoje: baixo e dormente. O dado fica protegido (nada é apagado indevidamente) e pela tela o operador só vê os próprios links; só é alcançável por chamada direta à API.
- O que fazer: quando nenhuma linha for afetada, responder que o link não foi encontrado, em vez de sucesso.
- Como verificar: pedir a exclusão de um link de outra empresa devolve não encontrado, e o link continua existindo; apagar o próprio link continua devolvendo sucesso e apagando de verdade.
- Aceite (H1): Dado um pedido de exclusão de link rastreável que não afeta nenhuma linha, Quando processado, Então a resposta diz que não foi encontrado, E nunca declara sucesso.
- Prioridade: baixa. RFs: RF-CONV-014. Descoberto na análise do {AUD-31} (2026-07-15).
- Sintoma: existe um ajuste que define o tamanho do endereço curto dos links rastreáveis, mas a função que gera o endereço ignora esse ajuste e usa um tamanho fixo. O administrador muda o valor, salva, e nada muda.
- Causa: o valor está gravado nos ajustes, mas o gerador do endereço nunca o lê.
- O que fazer: ou o gerador passa a ler o ajuste, ou o ajuste sai do painel. Ajuste que não faz nada é pior que ajuste inexistente, porque promete controle que não existe (admin-editable-first vale nos dois sentidos: o que está no painel tem que valer).
- Nota de contexto: é a mesma classe de defeito já mapeada em outro sistema interno nosso, onde mais da metade dos ajustes do painel não fazia nada. Vale conferir se há outros ajustes mortos neste produto.
- Como verificar: mudar o tamanho no painel e criar um link novo produz endereço com o tamanho escolhido.
- Aceite (H1): Dado que o administrador altera o tamanho do endereço curto, Quando um link novo é criado, Então o endereço respeita o tamanho configurado.
- Entregue 2026-07-24 (merge 1dffd8e, migration 107): o gerador de slug do RPC create_trigger_link passou a ler shortlink_slug_length (clamp 4..16, fallback 7), tornando o ajuste do painel efetivo. O review achou e a mesma fatia corrigiu um overflow (string de muitos dígitos estourava o ::int e quebraria a criação de links para todas as empresas): o parse passou a ser via numeric + LEAST, à prova de overflow. Provado por qa com números reais (5→5, 12→12, 2→4, 40→16, inválido→7), impersonate {AUD-32} intacto, Hiit intacta.
- Prioridade: média. RFs: RF-CONT (gestão de contatos). Descoberto pelo qa do {AUD-31} (2026-07-15), não investigado.
- Sintoma: durante navegação normal do painel, uma leitura de contato por identificador devolveu erro 400 na camada de dados. Não se sabe ainda se aparece como falha na tela ou se é silencioso.
- Causa provável: a confirmar. Suspeitas iniciais: pedido de coluna que não existe mais, ou contato já excluído. Precisa reproduzir antes de qualquer conserto.
- O que fazer: reproduzir, achar a origem da chamada, e corrigir a causa. Se for coluna inexistente, é a mesma família de defeito de consulta que já apareceu na mesclagem de contatos ({AUD-10}).
- Como verificar: navegar as telas de contato sem nenhuma leitura devolvendo 400.
- Aceite (H1): Dado a navegação normal pelas telas de contato, Quando as leituras acontecem, Então nenhuma devolve erro, E nenhuma falha fica silenciosa na tela.
- Prioridade: P0, vivo e reproduzido. RFs: RNF-010 (perímetro autenticado, criado por causa deste achado), RNF-001 (isolamento, agora também de escrita), RF-AUTO-002 (gatilhos, não pode regredir). Descoberto em 2026-07-15, no planejamento do {AUD-43}.
- Sintoma: o endereço que recebe os eventos do sistema responde sucesso a qualquer pessoa da internet, sem login nenhum. Quem chamar, informando a empresa alvo, faz o sistema executar as automações ativas daquela empresa contra um contato escolhido: as ações enviam WhatsApp e e-mail de verdade ao contato e consomem cota de execução. Não é endereço esquecido: está vivo e é usado pela própria tela.
- Não é falha geral de autenticação: outros endereços do mesmo arquivo recusam corretamente quem não está logado, o que prova que o guardião existe, funciona em produção e que este endereço passou batido.
- Racional honesto (uma primeira tese caiu na conferência; fica registrada a versão certa): o identificador da empresa não é público, ninguém o publica e o isolamento do banco está de pé. O ponto é outro: o identificador da empresa é identificador, não credencial. Ele nunca muda, é conhecido por todo membro e por todo ex-membro, e como não existe checagem de usuário nenhuma, excluir um usuário não revoga nada. Um ex-funcionário, um cliente que saiu ou um prestador desligado mantém, para sempre e sem nenhuma credencial, o poder de disparar mensagem real aos contatos daquela empresa. Ataque anônimo em massa não é viável (o identificador é sorteado e não há como enumerá-lo), então o atacante realista é quem já teve acesso, não um desconhecido da internet. Isso não rebaixa o card: rebaixa a premissa, e o conserto é o mesmo.
- Alcance hoje: dano limitado, falha viva. As três automações que existem em produção pertencem a empresas de teste; a empresa cliente não tem automação nenhuma. Vira dano real no dia em que uma empresa real criar a primeira automação.
- O que fazer: exigir, no próprio endereço, sessão válida e vínculo com a empresa alvo antes de qualquer efeito, nesta ordem: validar o pedido, recusar quem não está logado, recusar quem não tem acesso àquela empresa, e só então executar. Nível de acesso: qualquer membro da empresa (ou o Super Admin), não apenas dono ou administrador, porque os eventos correspondem a ações que o membro comum já faz legitimamente pela tela; exigir mais derrubaria o membro comum e seria regressão, não conserto. Não bloquear no servidor de borda: o endereço é legitimamente chamado pelo navegador do usuário, e a borda não sabe validar sessão.
- O que não pode quebrar: as automações disparadas pela tela ao criar contato, marcar e desmarcar tag, mover etapa e ganhar ou perder oportunidade; e o Super Admin em modo entrar como empresa. Os emissores internos do servidor não passam por este endereço e não são afetados.
- Armadilha de diagnóstico: a tela dispara o evento e não confere a resposta, então uma recusa indevida não aparece na tela: o evento simplesmente some. Por isso o aceite tem que ser provado por execução registrada no banco, nunca por "a tela não deu erro". É a mesma doença de tela que finge sucesso que a Onda AUD vem corrigindo.
- Como verificar: contra uma empresa de teste que tenha automação ativa, enviar o mesmo pedido quatro vezes mudando só a credencial: sem login recusa, com credencial inválida recusa, com credencial de quem é de outra empresa recusa, e em nenhum dos três nasce execução nova; com credencial de um membro daquela empresa, responde sucesso e a automação executa. O par negativo só vale contra uma empresa onde o par positivo prova que executa. Depois, pela tela: criar contato e ver a automação rodar, e repetir como Super Admin em modo entrar como empresa. Usar contato de teste: as automações enviam mensagem de verdade.
- Aceite (H1): Dado um pedido de disparo de evento para uma empresa que tem automação ativa naquele gatilho, Quando o pedido não traz sessão válida de alguém com acesso àquela empresa, Então o sistema recusa e nenhuma execução nova é criada; E Quando traz a sessão de um membro daquela empresa ou do Super Admin, Então responde sucesso e a automação executa.
- Prioridade: alta, sistêmica. RFs: RNF-010 (perímetro autenticado). Descoberto em 2026-07-15, no planejamento do {AUD-47}.
- Sintoma: o servidor de borda reescreve qualquer endereço que comece com o prefixo da API e o entrega ao servidor de integrações. Efeito: toda rota interna daquele servidor fica alcançável pela internet, tenha ou não guardião. É o mesmo motor já registrado no {AUD-27} (que tratou das rotas que ficaram mortas) e no {AUD-26} (que tratou de três endereços sem autenticação).
- Causa do card, dita sem maquiagem: o {AUD-26} auditou esta classe por lista curada, olhou três endereços e deixou passar justamente o do {AUD-47}, que estava vivo o tempo todo. É exatamente a falha de método já registrada no {AUD-35}: auditoria por lista curada propaga furo. Não é falta de atenção, é o método errado.
- O que fazer: enumerar por script, não a olho e não por amostra, todas as rotas do servidor de integrações, cruzando três colunas: a rota existe, tem guardião de autenticação, tem quem a chame. Só assim se sabe se há um terceiro endereço aberto escondido. Cada rota sem guardião vira decisão explicita: ou ganha guardião, ou é declarada pública por desenho com justificativa registrada, ou é removida.
- Pista levantada nesta sessão, a confirmar pela varredura: o disparo de conversões de anúncio aparece sem checagem de segredo visível na leitura de código, ao contrário das rotas agendadas irmãs. Não foi confirmado, e é justamente o tipo de dúvida que só a enumeração exaustiva resolve.
- Como verificar: existe uma lista completa, gerada por script e conferível, de toda rota alcançável pelo prefixo da API, com o estado do guardião de cada uma; nenhuma rota fica sem decisão registrada; e as que deviam ter guardião recusam quem não está logado numa requisição real.
- Aceite (H1): Dado o conjunto de todas as rotas alcançáveis pela internet, Quando a varredura por script é executada, Então cada rota aparece classificada como com guardião, sem guardião mas pública por desenho, ou removida, E nenhuma rota sem guardião permanece sem decisão registrada.
- Prioridade: alta. RFs: RF-LEAD (captura por webhook), RF-AUTO-002 (gatilhos). Descoberto em 2026-07-15, na conferência do {AUD-47}.
- Sintoma: um lead entra pelo caminho público de captura por webhook, o contato é criado normalmente, e a automação de novo contato nunca roda. Nada avisa. Quem configurou a captura vê o contato aparecer e supõe que o resto aconteceu.
- Causa (lida no código, não suposta): o caminho de captura chama o motor de eventos informando o nome do evento num campo chamado "type", mas o motor lê um campo chamado "event_type". Como o campo que ele lê chega vazio, o motor cai na primeira linha de proteção, que devolve sem fazer nada, e volta em silêncio. O conteúdo do evento também está na forma errada, com o identificador do contato solto no topo em vez de dentro do pacote de dados.
- Mesma família do {AUD-43} e do {AUD-42}: o produto promete um comportamento, a tela não acusa nada, e o comportamento não acontece. Aqui é pior que gatilho inexistente, porque este gatilho existe e funciona pelos outros caminhos: só este caminho o chama errado.
- Confirmado no planejamento do {AUD-43} (2026-07-15), com o ponto exato localizado no caminho público de captura: o conserto é do tamanho de duas chaves (o nome do campo do evento e a forma do pacote de dados). Já estava anotado no gate de planejamento do {AUD-47}, na véspera, e não foi corrigido ali: ficou registrado e a fila seguiu. Fica explícito aqui para não se perder de novo, porque é achado barato de corrigir e caro de esquecer.
- É um décimo segundo gatilho mentindo, escondido dentro dos onze que o {AUD-43} deu como funcionando: o gatilho de novo contato funciona de verdade pelos outros caminhos, e foi por isso que a contagem do {AUD-43} não o pegou. Só este caminho o chama errado.
- Irmão do {AUD-57}: o agendamento público também cria contato pela porta pública e também não dispara o gatilho de novo contato. As duas portas públicas de entrada de contato estão mudas, pela mesma doença, e por isso a varredura dos pontos que criam contato tem que ser exaustiva, não por amostra.
- O que fazer: chamar o motor de eventos com o nome de campo que ele lê e com o conteúdo na forma que ele espera. Conferir de passagem, pelo mesmo critério e não por amostra, se há outros pontos chamando o motor com a forma errada.
- Como verificar: com uma automação ativa no gatilho de novo contato, enviar um lead pelo caminho público de captura por webhook e confirmar que o contato foi criado e que a automação executou, com a execução registrada. Hoje o contato é criado e não existe execução nenhuma.
- Aceite (H1): Dado uma automação ativa no gatilho de novo contato, Quando um lead entra pelo caminho público de captura por webhook, Então o contato é criado E a automação executa, E a execução fica registrada.
- Entregue em 2026-07-15 (merge 5e4f590), no mesmo dia em que nasceu, com o webhook reiniciado e a prova rodada em produção. A causa era exatamente a lida: o caminho de captura chamava o motor de eventos com o campo "type" em vez de "event_type", e com o identificador do contato solto fora do pacote de dados; agora chama com o nome de campo certo e o pacote na forma certa. A guarda do motor de eventos deixou de ser muda: evento malformado agora fica registrado no log, em vez de sumir em silêncio. Prova por TDD: o teste reprovava antes do conserto (nenhuma execução nascia) e passa depois (duas execuções, contato certo); reenviar o mesmo lead não dispara de novo (dedup não dispara); a baseline de execuções voltou ao normal (treze), a Hiit segue intacta (1503 contatos), e nenhuma mensagem real saiu durante o teste. Gates: plan APPROVED, qa PASS, review APPROVED, zero Critical, checagem de antirregressão limpa, os cinco comportamentos anteriores provados sobreviventes.
- A verdade incômoda que esta fatia revelou, sem maquiagem: o card supunha "um quebrado ({AUD-49}) mais um irmão ({AUD-57})". O planejamento varreu por critério, não por amostra, e achou dezoito pontos do produto que criam contato, dos quais cinco emitem o evento (quatro provados no backend e um, o do frontend, não provado; o número foi corrigido de quatro para cinco em 2026-07-16); são, de fato, um quebrado e treze mudos. O dado que mais incomoda: os contatos dos últimos trinta dias vieram do livechat (seis), do agendamento público (quatro) e do formulário (três); zero vieram pelo webhook de captura de lead. Os três caminhos com tráfego real de verdade continuam mudos, e esta entrega consertou justamente o caminho que não tem tráfego. O defeito era real e o card procede, mas quem ler "{AUD-49} fechado" não deve supor que o gatilho de contato criado passou a funcionar: não passou, na maior parte dos caminhos. O RF-AUTO-002 continua violado pelos outros caminhos, e este card não o entrega. Os treze pontos mudos, a raiz do desenho e mais três achados do qa e do review viraram os cards {AUD-65} a {AUD-70}.
- Nota do {AUD-67} (2026-07-15): o teste original desta fatia usou só lead sem o campo de mensagem, e por isso não pegou que o gatilho de novo contato também não disparava para lead com mensagem, por um TypeError separado na gravação da nota. Por cerca de duas horas este card ficou marcado como concluído enquanto o próprio H1 dele era violado por um ramo inteiro do lead. Quem consertou foi o {AUD-67}, e o qa daquela fatia revalidou este card nos dois ramos, com e sem mensagem: hoje o marcador de concluído é verdade de fato. Fica registrado sem suavizar: o teste da época desviou do defeito, e a lição é a mesma da regra de falseabilidade, confira sempre se o teste exercita o ramo que o H1 descreve.
- Prioridade: média (dormente hoje, por falta de conta cadastrada). RFs: RF-CONV (conversas por e-mail), RNF-003 (confiabilidade da entrega assíncrona). Descoberto em 2026-07-15, na conferência do {AUD-43}.
- Sintoma: o agendador chama a coleta de e-mail de 5 em 5 minutos e recebe recusa por credencial inválida. A coleta nunca roda. Consequência em cadeia: o gatilho de e-mail recebido tem emissor de verdade (é o coletor que o dispara), mas como o coletor não roda, o gatilho não acontece na prática.
- Causa (provada, não suposta): o agendador manda o segredo no cabeçalho da chamada, e esta rota lê o segredo apenas no endereço. Como ela não olha o cabeçalho, recusa. É a única rota agendada assim: as irmãs conferidas ou aceitam o segredo nos dois lugares (lembretes, não comparecimento, renovação de acesso e faturamento) ou leem só o cabeçalho (sincronização de agenda, passos agendados de automação). O padrão certo já existe no mesmo arquivo, aplicado às irmãs, e esta ficou para trás. É o mesmo sintoma que o {AUD-07} corrigiu no faturamento, que recusava desde 2026-04-19 e nunca tinha gerado uma fatura.
- Risco hoje: dormente, e a razão é honesta: não há nenhuma conta de e-mail cadastrada, então não há o que coletar e ninguém sente. Vira defeito no minuto em que a primeira conta for cadastrada, e aí a conversa por e-mail simplesmente não acontece, sem aviso.
- O que fazer: fazer esta rota aceitar o segredo do mesmo jeito que as irmãs já aceitam. E registrar a recusa no log, porque foi por isso que isto passou despercebido: a recusa não deixa rastro nenhum, e rota que morre em silêncio não aparece em lugar nenhum. Vale a pena olhar, no mesmo movimento, se outra rota agendada sofre do mesmo (o {AUD-48} cobre a varredura exaustiva).
- Como verificar: com uma conta de e-mail cadastrada, o agendador roda sozinho e a coleta aparece no registro do serviço a cada ciclo; um e-mail que chega vira mensagem na conversa e dispara a automação de e-mail recebido.
- Aceite (H1): Dado o agendador chamando a coleta de e-mail do jeito que ele chama hoje, Quando a chamada acontece, Então a coleta executa e registra o resultado, E nenhuma chamada legítima é recusada.
- Prioridade: alta (drift de documento). RFs: RF-CONV-014 (Links rastreáveis, Média), RF-AUTO-002 (Gatilhos, Alta). Descoberto em 2026-07-15, no planejamento do {AUD-43}. Irmão do {AUD-31}.
- Sintoma: o DRS prometia, em dois requisitos, que o clique num link rastreável servia de gatilho de automação. A tela nem oferece esse gatilho, e o clique não chega a lugar nenhum: o endereço curto conta o clique, redireciona o visitante, e acaba ali.
- Evidência: o clique em link não aparece em nenhuma das quatro listas de gatilhos do editor. O endereço curto registra o clique e redireciona sem avisar o motor de eventos. Pior: o registro do clique é gravado com o contato fixado como nulo, ou seja, ninguém sabe quem clicou. Sem contato atribuído, o aceite do próprio RF-AUTO-002 (o contato é inscrito na automação) é impossível hoje: não há a quem inscrever.
- Por que é prioridade, mesmo sendo dormente na operação: é drift do documento na direção mais perigosa, a inversa. O caso comum é o produto estar atrás do documento; aqui o documento afirmava como existente o que nunca existiu. Documento que mente é defeito, não falta de feature. O {AUD-31} devolveu criar, listar e apagar os links, e não alegou o contrário: o aceite dele era só responder sem erro de configuração.
- Risco antes da entrega: dormente na operação (não havia automação de clique porque o gatilho nem era oferecido). O RF-CONV-014 e o RF-AUTO-002 foram reconciliados em 2026-07-15 e este card era a dívida de produto que sobrou dessa reconciliação, paga na mesma data.
- O que foi feito: o link curto passou a carregar o contato desde o momento do envio, por um id opaco de envio de 32 hex emitido por par de link e contato pela RPC issue_link_token, que exige que o link e o contato sejam da mesma empresa; o registro do clique passou a gravar quem clicou e a lançar a linha no histórico do contato, aba Atividade, tipo link_click; a rota responde o redirecionamento primeiro e só então emite o evento link.clicked em processo, e só com contato atribuído; clique anônimo, token de outro link ou token de outra empresa redirecionam e contam, sem atribuir e sem disparar; o endereço curto passou a ser único em todo o produto, não mais só por empresa; e o RF-AUTO-002 foi emendado para nomear o clique entre os gatilhos oferecidos, com a merge tag {{link.<slug>}} expandindo para a URL com o token daquele contato a partir do ajuste shortlink_base_url, editável no painel.
- Como verificar: com uma automação ativa no gatilho de clique em link, mandar um link rastreável para um contato de teste, clicar como aquele contato e confirmar que o clique aparece no histórico daquele contato e que a automação executou para ele.
- Aceite (H1): Dado um link rastreável enviado a um contato, Quando aquele contato clica, Então o clique é registrado no histórico dele com o contato identificado, E a automação ativa com o gatilho de clique dispara para ele, E o RF-AUTO-002 passa a nomear o clique entre os gatilhos oferecidos.
- Prioridade: média. RFs: RF-AUTO-002 (Gatilhos), RF-CAL (lembretes de agendamento). Descoberto em 2026-07-15, no planejamento do {AUD-43}. Decisão de produto tomada em 2026-07-15: deixou de ser pendência e virou trabalho especificado.
- Decisão (2026-07-15): o sistema para de mandar o lembrete por conta própria, e o lembrete passa a ser uma automação que a empresa monta, com o texto que ela quiser. O gatilho de lembrete de agendamento voltou ao conjunto do RF-AUTO-002, que passou de treze para quinze gatilhos nomeados. Decisão complementar de 2026-07-15, que fechou a última pendência deste card: a subconta nova nasce sem automação nenhuma, e quem quiser lembrete monta a automação. A regra de continuidade é assimétrica de propósito, e os dois casos estão escritos no RF-AUTO-002: empresa que já existe recebe a automação provisionada e ativa; subconta nova nasce limpa.
- Sintoma (o que motivou a decisão): o gatilho saiu da lista no {AUD-43} porque não tem emissor. Só que ligá-lo não é criar o emissor e pronto: o lembrete já é enviado hoje, sozinho, pelo agendador do sistema, com texto fixo, pelos canais definidos numa configuração da empresa, marcando o agendamento como lembrado.
- Evidência: existem, portanto, dois donos possíveis para o mesmo lembrete. Se o gatilho passar a existir sem que o agendador pare, o contato recebe dois lembretes do mesmo agendamento, um de cada caminho. A decisão define o dono único: a automação.
- Risco hoje: nenhum, o gatilho ainda não é oferecido. O risco nasce se alguém criar o emissor sem desligar o agendador, ou desligar o agendador sem provisionar a automação equivalente.
- O que fazer: (1) criar o emissor do lembrete no momento em que o agendador hoje dispara, e oferecer o gatilho na lista; (2) desligar o envio próprio do agendador na mesma entrega, nunca em entregas separadas, porque a janela entre as duas é exatamente o lembrete duplicado; (3) transformar o texto fixo de hoje em modelo editável pela empresa, com as variáveis do agendamento e do contato; (4) na virada, provisionar para cada empresa que hoje tem lembrete ativo a automação equivalente, já ativa, montada a partir da configuração de canais vigente e reproduzindo o texto atual, para que nenhuma empresa perca o lembrete sem ter decidido perder; empresa que hoje está com o lembrete desligado recebe a automação inativa; e (5) na criação de subconta nova, não provisionar automação nenhuma, nem de lembrete nem de qualquer outra: a subconta nasce limpa, e a automação de lembrete só existe nela se a empresa montar.
- Regressão a declarar (o que esta mudança perde): hoje o lembrete sai sem a empresa montar nada. Depois desta entrega, empresa sem automação de lembrete fica sem lembrete. Para as empresas que já existem a perda é proibida, e o item (4) a impede. Para a subconta nova não há um "hoje" a preservar, e a escolha foi decidida em 2026-07-15, com o registro da conversa no Questionário de Elicitação, pergunta {Q1}: nasce sem nenhuma, e quem quiser lembrete monta a automação. A consequência foi aceita e não maquiada: a subconta nova que não montar nada nunca manda lembrete, e quem não souber que o recurso existe fica sem. Isso foi decidido, não esquecido, e o item (5) do que fazer é justamente não provisionar nada. Contramedida proposta, ainda sem aval e fora do aceite deste card: devolver o modelo de lembrete de agendamento à galeria de modelos (RF-AUTO-006), que o {AUD-43} removeu porque entregava automação quebrada em um clique, defeito que esta entrega elimina ao criar o emissor; o modelo faz o recurso ser descoberto e continua exigindo que a empresa clique e ative, que é diferente de nascer montado e ativo.
- Como verificar: um agendamento de teste com lembrete configurado produz exatamente uma mensagem de lembrete ao contato, nunca duas; desligada a automação, nenhuma mensagem sai (prova de que o agendador não manda mais nada por conta própria); editado o texto do modelo, a mensagem que chega ao contato traz o texto novo; e uma empresa que recebia lembrete antes da virada continua recebendo depois dela, sem ter montado nada; e uma subconta criada depois da virada nasce com a lista de automações vazia, e um agendamento de teste nela não produz lembrete nenhum enquanto a empresa não montar e ativar a automação.
- Aceite (H1): Dado uma empresa com lembrete de agendamento ativo antes da virada, Quando a entrega sobe e um agendamento de teste chega ao momento do lembrete, Então o contato recebe exatamente uma mensagem de lembrete, vinda da automação e não do agendador, E o texto é o do modelo editável da empresa, E desligar a automação faz o lembrete parar de sair por completo, E, no caso da subconta nova, Dado uma subconta criada depois da virada, Quando a lista de automações dela é aberta, Então tem zero automações, E um agendamento de teste nessa subconta não produz lembrete nenhum até que a empresa monte e ative a automação.
- Prioridade: média. RF: RF-AUTO-002 (Gatilhos). Descoberto em 2026-07-15, no planejamento do {AUD-43}. Decisão de produto tomada em 2026-07-15: deixou de ser pendência e virou trabalho especificado.
- Decisão (2026-07-15): a opção volta para a lista, e ao escolhê-la a empresa marca quais campos importam (por exemplo só telefone e estágio). Mudou outro campo, não dispara. O gatilho voltou ao conjunto do RF-AUTO-002, e o filtro por campo é parte do requisito, não um extra opcional.
- Sintoma (o que motivou a decisão): entre os gatilhos que saíram, este parece o mais fácil de devolver, porque o fato acontece o tempo todo e é trivial de detectar. É justamente por isso que é o mais perigoso: sem filtro, ele dispara a cada edição de qualquer campo de qualquer contato, inclusive as edições que o próprio sistema faz. Vira mangueira de incêndio: corrigir um acento no nome mandaria mensagem ao cliente.
- Evidência: a referência de paridade do produto oferece este gatilho com filtro por campo, e não por acaso. Sem filtro, uma automação de contato atualizado que edita o contato como ação se dispara de novo, em laço.
- Risco técnico (levantado no planejamento do {AUD-43}): o ponto onde a edição é detectada hoje cobre só o caminho da tela. A importação de contatos, a interface de programação e a própria automação escrevem no contato por outros caminhos e ficariam mudas. Como o RF-AUTO-002 exige a regra por canal (nenhum gatilho vale só para parte dos caminhos por onde o fato acontece), o emissor tem que nascer onde o campo muda de verdade, não só no formulário da tela.
- Risco hoje: nenhum, o gatilho ainda não é oferecido.
- O que fazer: (1) ao escolher o gatilho, oferecer a seleção de quais campos observar, sem opção de "qualquer campo"; (2) emitir o evento em todos os caminhos por onde o campo muda (tela, importação, interface de programação e ação de automação), não só no da tela; (3) guarda contra laço: a edição feita pela própria automação não a redispara.
- Como verificar: automação ativa no gatilho, filtrada por um campo; editar outro campo não dispara nada; editar o campo escolhido dispara uma vez só; importar uma planilha que muda o campo escolhido dispara; e uma automação que edita o campo escolhido como ação dela não se redispara.
- Aceite (H1): Dado uma automação ativa no gatilho de contato atualizado, filtrada pelo campo telefone, Quando qualquer outro campo do contato é editado por qualquer caminho, Então nada dispara, E quando o telefone é editado a automação dispara exatamente uma vez, tanto pela tela quanto pela importação quanto pela interface de programação, E a automação que edita o telefone como ação dela não se redispara.
- Prioridade: baixa. Fora do escopo atual do RF-AUTO-002 por decisão firmada. Descoberto em 2026-07-15, no planejamento do {AUD-43}.
- Sintoma: o fato "o status da conversa mudou" acontece em cinco lugares diferentes do produto. Um deles é escrito pelo próprio motor de automação, quando ele executa uma ação. Emitir o evento nesses cinco pontos sem cuidado cria laço: a automação muda o status, o que dispara a automação, que muda o status.
- Evidência: quatro dos cinco pontos são ações humanas ou de canal; o quinto é o passo de automação. Um gatilho ingênuo não distingue os dois.
- Risco hoje: nenhum, o gatilho saiu da lista no {AUD-43} e não é oferecido.
- O que fazer: se voltar, tratar o laço explicitamente (o evento não nasce quando quem mudou o status foi o motor) e cobrir os cinco pontos, não um. Emendar o RF-AUTO-002 antes.
- Como verificar: automação ativa no gatilho; mudar o status pela tela dispara uma vez; a automação mudando o status como ação não se redispara.
- Aceite (H1): Dado uma automação ativa no gatilho de status da conversa alterado, Quando o status muda por ação humana em qualquer um dos caminhos, Então a automação dispara uma vez, E quando quem muda o status é a própria automação, nada dispara.
- Prioridade: baixa, dependente da V2 de cobrança. Fora do escopo atual do RF-AUTO-002 por decisão firmada. Descoberto em 2026-07-15, no planejamento do {AUD-43}.
- Sintoma: os dois gatilhos saíram da lista no {AUD-43}. Não estão no documento e não têm como existir de verdade hoje.
- Evidência: a cobrança da V1 é Pix manual, sem gateway de pagamento e sem aviso automático de pagamento. "Pago" é uma afirmação humana digitada na tela, não um fato de pagamento. Um gatilho de fatura paga que dispara quando alguém digita "pago" promete mais do que entrega.
- Correção importante ao raciocínio anterior, para não se repetir: o processamento diário de faturas que já existe não serve de gancho para fatura vencida. Ele opera sobre a cobrança da Modulareasy contra as empresas que usam o sistema; o gatilho seria sobre a cobrança da empresa contra os clientes dela. São tabelas diferentes e donos diferentes. Pendurar um no outro faria a automação da empresa disparar na própria mensalidade dela. É erro de categoria, não atalho.
- Risco hoje: nenhum, os gatilhos não são oferecidos.
- O que fazer: adiar para quando a cobrança automática existir (V2). Fatura vencida ainda vai precisar de um processo diário novo, sobre as faturas do cliente, e não de reaproveitar o que existe.
- Como verificar: só depois da V2 de cobrança.
- Aceite (H1): Dado a cobrança automática entregue na V2, Quando uma fatura do cliente é paga ou vence, Então o gatilho correspondente dispara sobre a fatura certa (a do cliente da empresa, nunca a mensalidade da empresa), E o RF-AUTO-002 foi emendado antes do código.
- Prioridade: média. RF: RF-AUTO-043 (Executar uma automação à mão para um contato escolhido), criado em 2026-07-15 para atender esta decisão. Descoberto em 2026-07-15, no planejamento do {AUD-43}. Decisão de produto tomada em 2026-07-15: deixou de ser pendência e virou trabalho especificado.
- Decisão (2026-07-15): o botão é desejado. É feature nova, não correção de mentira, e por isso ganhou requisito próprio (RF-AUTO-043) antes de virar código. O uso principal é testar uma automação antes de ativá-la.
- Sintoma: a lista de gatilhos oferecia "execução manual", e o nome prometia um botão que a tela não tem. No {AUD-43} o nome foi corrigido para dizer a verdade (a opção passou a se apresentar como "sem gatilho automático, chamada por outra automação"), o que fecha a mentira. O botão em si continua não existindo.
- Evidência: não há, em nenhuma tela do módulo de automações, uma ação de executar agora, disparar ou rodar para um contato escolhido.
- Risco hoje: nenhum. O valor continua servindo ao seu uso legítimo, que é uma automação ser chamada por outra como sub-fluxo; foi por isso que ele não saiu da lista no {AUD-43}, só mudou de nome.
- Cuidado ao construir: executar uma automação envia mensagem de verdade ao contato escolhido e consome cota, como o {AUD-47} mostrou ao encontrar o barramento de eventos aberto para qualquer pessoa da internet. O botão tem que avisar isso antes de confirmar, exigir sessão válida com vínculo à empresa alvo (RNF-010) e registrar quem mandou executar.
- O que fazer: (1) oferecer na tela da automação a ação de executar agora, com escolha do contato; (2) rodar a automação na hora para aquele contato, inclusive quando ela está em rascunho (é o caso de uso de teste) e quando ela não tem gatilho automático; (3) avisar antes de confirmar que as ações são reais; (4) registrar a execução no histórico da automação e do contato, marcada como execução manual e com o autor; (5) entregue o botão, corrigir o rótulo do gatilho de execução manual, que hoje diz que a automação só roda por chamada de outra automação.
- Como verificar: com uma automação sem gatilho automático, o administrador escolhe um contato, manda executar pela tela e a execução aparece registrada com o nome de quem executou; o mesmo funciona com uma automação em rascunho; o aviso de que as ações são reais aparece antes da confirmação; e uma chamada sem sessão válida não executa nada.
- Aceite (H1): Dado uma automação em rascunho e um contato escolhido, Quando o administrador manda executar agora pela tela e confirma o aviso de que as ações são reais, Então a automação roda para aquele contato na hora, E a execução aparece no histórico da automação e no histórico do contato, identificada como execução manual e com o autor registrado, E o rótulo do gatilho de execução manual passa a mencionar o botão, deixando de dizer que a automação só roda por chamada de outra automação.
- Prioridade: alta. Mesma família do {AUD-49}. RFs: RF-AUTO-002 (Gatilhos, Alta), RF-CAL (agendamento público). Descoberto em 2026-07-15, no planejamento do {AUD-43}.
- Sintoma: uma pessoa agenda pela página pública de agendamento, o contato é criado do jeito certo e marcado como vindo do agendamento público, e a automação de novo contato não roda. Nada avisa. Quem configurou uma automação de boas-vindas vê o contato aparecer na lista e supõe que o resto aconteceu.
- Evidência: o ponto que cria o contato no agendamento público não avisa o motor de eventos. O gatilho de novo contato existe e funciona pelos outros caminhos; é esta porta que não o chama.
- Por que é mais grave do que parece: é uma porta pública, ou seja, exatamente por onde entra gente de fora que ninguém está olhando em tempo real. Junto com o {AUD-49} (o webhook público de captura de lead), são duas das portas públicas de entrada de contato, e as duas estão mudas, pelo mesmo tipo de descuido. O contato entra sem automação nenhuma e o silêncio é total.
- Risco hoje: real. Diferente dos gatilhos sem emissor do {AUD-43}, aqui o gatilho está na lista, funciona quando testado pela tela, e falha calado justamente no caminho de quem chega de fora.
- O que fazer: avisar o motor de eventos quando o agendamento público criar contato. E, no mesmo movimento, varrer todos os pontos que criam contato, não por amostra, conferindo um a um quais avisam e quais não avisam: as duas portas públicas caíram no mesmo buraco, é provável que a varredura ache mais.
- Como verificar: com uma automação ativa no gatilho de novo contato, agendar pela página pública usando um contato que ainda não existe, e confirmar que o contato é criado e que a automação executou, com a execução registrada.
- Aceite (H1): Dado uma automação ativa no gatilho de novo contato, Quando alguém que ainda não é contato agenda pela página pública, Então o contato é criado E a automação executa, E a execução fica registrada.
- Prioridade: alta. RFs: RF-AUTO-002 (Gatilhos, Alta), RF-CONV (canais de entrada do inbox unificado). Descoberto em 2026-07-15, no planejamento do {AUD-43}.
- Sintoma: o gatilho de mensagem recebida está na lista, funciona, e por isso ninguém desconfia. Mas ele só nasce quando a mensagem chega por WhatsApp ou por e-mail. Se a mensagem entra por SMS, pelo chat do site, pelo Instagram ou pelo Messenger, a mensagem aparece na conversa normalmente e a automação não roda.
- Evidência: o evento é emitido no caminho do WhatsApp e no do e-mail, e não é emitido nos quatro outros caminhos de entrada de mensagem.
- Por que é mais grave do que parece: um gatilho parcial é pior que um gatilho morto. O morto nunca funciona e a pessoa percebe no primeiro teste; este funciona no primeiro teste, e a pessoa conclui, com razão aparente, que funciona em todos os canais. O produto exige o SMS como canal (é um dos canais do pilar de Conversas), então um gatilho que o ignora não cumpre o RF-AUTO-002, que agora nomeia "mensagem recebida" sem ressalva de canal.
- Risco hoje: real, e é o tipo de defeito que só aparece quando alguém reclama que "a automação funcionava e parou", quando na verdade ela nunca valeu para aquele canal.
- O que fazer: emitir o evento em todos os caminhos de entrada de mensagem, no ponto onde a mensagem entra, e de uma vez, não canal a canal conforme alguém reclama. Se algum canal ficar de fora por decisão, a decisão vai para o documento: a lista tem que dizer a verdade também dentro do gatilho, não só sobre a existência dele.
- Como verificar: com uma automação ativa no gatilho de mensagem recebida, mandar uma mensagem de entrada por cada canal conectado, um por um, e confirmar que cada canal produz uma execução.
- Aceite (H1): Dado uma automação ativa no gatilho de mensagem recebida, Quando chega uma mensagem por qualquer canal de entrada do produto, Então a automação dispara para aquele contato, E nenhum canal de entrada fica de fora sem estar declarado no DRS.
- Prioridade: média. RFs: RF-AUTO-002 (Gatilhos, Alta), RF-BILL (limites e cota por plano). Descoberto em 2026-07-15, no planejamento do {AUD-43}.
- Sintoma: o gatilho de limite de armazenamento atingido está na lista e tem emissor de verdade, mas o emissor só é consultado num único ponto do produto: quando alguém envia um e-mail. Quem estoura a cota de outro jeito (subindo arquivo, anexando mídia, importando) nunca dispara o aviso. A empresa passa do limite e ninguém é avisado.
- Evidência: a verificação é chamada de um lugar só, o envio de e-mail, embora a documentação escrita na própria função mande chamá-la "após qualquer operação que afete o uso de armazenamento". A instrução certa está escrita ao lado do código que não a segue, o que torna o defeito ainda mais claro: não é dúvida de desenho, é chamada faltando.
- Por que é mais grave do que parece: é um aviso que existe para proteger a cota e que não protege. Estourar a cota sem aviso é exatamente o cenário que este gatilho existe para evitar, e o caminho mais provável de estourar armazenamento é subir arquivo, não mandar e-mail.
- Risco hoje: real e silencioso.
- O que fazer: chamar a verificação em todos os pontos que mexem no armazenamento (upload de mídia, anexo em mensagem, importação), levantando esses pontos por varredura e não por memória.
- Como verificar: com uma automação ativa no gatilho de limite atingido, estourar a cota sem enviar e-mail nenhum, subindo arquivos até passar do limite, e confirmar que a automação disparou.
- Aceite (H1): Dado uma automação ativa no gatilho de limite de armazenamento atingido, Quando o uso ultrapassa o limite por qualquer operação que consome armazenamento, Então a automação dispara, E o disparo não depende de a empresa ter enviado um e-mail.
- Prioridade: média. RFs: RF-AUTO-002 (Gatilhos, Alta), RF-OPP (funis e oportunidades). Descoberto em 2026-07-15, no planejamento do {AUD-43}.
- Sintoma: mover um card no funil dispara os gatilhos que devem disparar (etapa alterada, oportunidade ganha, oportunidade perdida). Selecionar trinta e mover em massa não dispara nada. Mesma ação, resultado diferente, sem aviso nenhum.
- Evidência: o caminho de atualização em massa das oportunidades não avisa o motor de eventos; o caminho de uma em uma avisa. Os dois convivem na mesma tela.
- Por que é mais grave do que parece: a ação em massa é justamente a que as pessoas usam em volume. Quem arrasta trinta oportunidades para ganho no fechamento do mês perde trinta automações de uma vez, e o defeito é invisível: a tela mostra as trinta movidas, corretamente. O prejuízo é proporcional ao uso, e cresce com a adoção.
- Risco hoje: real, e cresce conforme o cliente usa mais o funil.
- O que fazer: o caminho em massa passa a emitir o mesmo evento que o caminho individual, uma vez por oportunidade movida. Conferir, no mesmo movimento, se as outras ações em massa do produto (tags em massa, exclusão em massa) têm o mesmo buraco. A pergunta certa é "toda ação em massa dispara o mesmo que a ação individual?", e ela vale para o produto inteiro, não só para o funil.
- Como verificar: com uma automação ativa no gatilho de etapa alterada, mover várias oportunidades de uma vez e confirmar que nasce uma execução por oportunidade movida, exatamente como acontece movendo uma a uma.
- Aceite (H1): Dado uma automação ativa num gatilho de oportunidade, Quando várias oportunidades são movidas de uma vez, Então nasce uma execução por oportunidade movida, E o resultado é igual ao de mover uma a uma.
Achados do planejamento do {AUD-51} (2026-07-15)
Quatro achados que apareceram ao planejar o {AUD-51} e que ficaram FORA daquela fatia, de propósito: nenhum deles serve ao aceite dele, e enfiá-los na mesma entrega inflaria o diff e faria o card fugir do próprio H1. Ficam aqui porque achado que não vira card é invisível para a fila. Os dois primeiros são defeitos reais em produção hoje; o terceiro é o limite declarado da entrega do {AUD-51}; o quarto depende de uma decisão de produto que ainda não foi tomada.
- Prioridade: alta. RFs: RF-AUTO-002 (Gatilhos, Alta), RF-AUTO-003 (Ações). Descoberto em 2026-07-15, no planejamento do {AUD-51}.
- Sintoma: uma automação que manda mensagem escrita com a variável do nome do contato chega ao contato com um buraco no lugar do nome. Não em todas: nos gatilhos de agendamento o nome aparece; na maioria dos outros, não.
- Evidência: quando o fato acontece, o evento que nasce leva só a identificação do contato, e não leva o nome, o telefone nem o e-mail. Quem monta o texto da mensagem lê esses valores do que veio no evento, e não vai buscá-los no cadastro do contato, então o que não veio vira vazio. Só os três caminhos de agendamento levam o nome junto, porque lá o nome do convidado viaja com o agendamento. A identificação do contato chega a ser passada para quem monta o texto, e é ignorada: hoje ninguém a usa para buscar o cadastro.
- Por que é mais grave do que parece: a automação roda, a mensagem sai, o registro diz que foi enviada, e o defeito só aparece no celular do cliente do cliente. Não há erro, não há falha, não há aviso: é sucesso fingido, o que o RF-CONV-054 condena. E acontece justo no caso mais comum que existe, contato criado mandando boas-vindas com o nome.
- Risco hoje: real e em produção, em qualquer automação que use variável de contato fora dos gatilhos de agendamento.
- O que fazer: quem monta o texto da mensagem passa a resolver as variáveis do contato a partir do cadastro, usando a identificação que já recebe, em vez de depender do que o evento levou por acaso. Conferir de uma vez todas as variáveis de contato oferecidas, e não só o nome.
- Como verificar: montar uma automação no gatilho de contato criado com uma mensagem que use o nome, o telefone e o e-mail do contato, criar um contato de teste com os três campos preenchidos, e conferir que a mensagem recebida traz os três valores. Repetir num gatilho de agendamento e confirmar que o que já funcionava continua funcionando.
- Aceite (H1): Dado uma automação que envia mensagem usando variáveis do contato, Quando ela dispara por qualquer um dos gatilhos do RF-AUTO-002, Então a mensagem recebida traz os valores do cadastro daquele contato em todas as variáveis usadas, E nenhuma variável de contato chega vazia quando o campo correspondente está preenchido no cadastro, E as automações de agendamento, que hoje já trazem o nome, continuam trazendo.
- Prioridade: média. RFs: RF-CONV-014 (Links rastreáveis, Média), RNF-001 (isolamento entre empresas). Descoberto em 2026-07-15, no planejamento do {AUD-51}.
- Sintoma: um usuário que participa de mais de uma empresa cria um link rastreável, e o link nasce numa das empresas dele sem que ele escolha e sem que a tela diga qual.
- Evidência: na criação do link, a empresa dona não vem da empresa em que o usuário está trabalhando. Ela é buscada na lista de empresas do usuário, e fica a primeira que aparecer, sem critério nenhum. Para quem atende uma empresa só o resultado é sempre certo por acaso, e é por isso que o defeito não aparece hoje.
- Por que é prioridade agora, e não antes: enquanto o link só contava clique, errar a empresa dona errava uma estatística. Depois do {AUD-51} a empresa do link é a empresa do evento e a empresa da automação que dispara, então errar a empresa dona passa a disparar a automação da empresa errada. O defeito é antigo; o que mudou foi o alcance dele.
- Risco hoje: baixo na operação (hoje quem atende várias empresas é a operação da Modulareasy), e sobe assim que alguém de duas empresas criar um link.
- O que fazer: a criação do link passa a receber a empresa em que o usuário está trabalhando, a mesma que a tela já mostra, e recusa criar o link se essa empresa não for uma das dele. Nada de escolher sozinho.
- Como verificar: com um usuário que participa de duas empresas, criar um link rastreável estando na segunda empresa e confirmar que o link nasceu na segunda, e não na primeira.
- Aceite (H1): Dado um usuário que participa de mais de uma empresa, Quando ele cria um link rastreável estando numa delas, Então o link nasce naquela empresa, E nunca em outra empresa do usuário, E a criação é recusada se a empresa indicada não for uma das dele.
- Prioridade: média. RFs: RF-AUTO-002 (Gatilhos, Alta), RF-CONV-014 (Links rastreáveis, Média). Descoberto em 2026-07-15, no planejamento do {AUD-51}. Depende do {AUD-51}.
- Sintoma: não é defeito, é o limite declarado da entrega do {AUD-51}. O gatilho de clique em link dispara com o clique em qualquer link da empresa, e o administrador não tem como dizer que só aquele link interessa.
- Evidência: a regra do gatilho de clique em link, no RF-AUTO-002, registra a escolha por escrito: qualquer link da empresa dispara, e a escolha de qual link fica neste card.
- Por que não foi feito junto: sem a tela que grave a escolha, o desvio no motor seria código morto, que é exatamente o que o {AUD-43} acabou de limpar do produto. Construir o filtro antes do seletor seria repetir o defeito que a onda anterior corrigiu.
- Risco hoje: nenhum enquanto a empresa tiver poucos links. Cresce com o número de links: quem tiver dez links e quiser automação para um deles vai receber o disparo dos dez.
- O que fazer: o gatilho de clique em link ganha a escolha do link na configuração, o construtor ganha o seletor que grava essa escolha, e o motor passa a comparar o link do clique com o link escolhido. Deixar sem escolha continua valendo e continua significando qualquer link, para não quebrar a automação de quem já montou. Aproveitar a passagem e resolver o endereço curto que a tela dos links monta na mão quando o sistema não devolve o endereço pronto: hoje o endereço do produto está escrito dentro do código, atrás de uma alternativa que a busca por texto não encontra, e o endereço já tem uma configuração própria editável no painel.
- Como verificar: com dois links rastreáveis na mesma empresa e uma automação configurada para o primeiro, clicar no segundo e confirmar que a automação não roda, e clicar no primeiro e confirmar que roda.
- Aceite (H1): Dado uma automação no gatilho de clique em link configurada para um link específico, Quando um contato clica em outro link da mesma empresa, Então a automação não roda, E, Quando o mesmo contato clica no link escolhido, Então a automação roda para ele, E uma automação sem link escolhido continua rodando para o clique em qualquer link da empresa.
- Prioridade: média. RFs: RF-CONV-014 (Links rastreáveis, Média), RF-CONV (Inbox e conversas). Descoberto em 2026-07-15, no planejamento do {AUD-51}. BLOQUEADO: depende da resposta da pergunta {Q2} do Questionário de Elicitação.
- Sintoma: o operador que digita uma variável numa conversa do Inbox manda a variável escrita, literal, para o contato. Quem faz isso com um link rastreável manda um link sem dono: ele redireciona e conta o clique, e não dispara automação nenhuma.
- Evidência: a expansão de variáveis existe só no caminho da automação. A mensagem digitada à mão no Inbox não passa por ela, então nem o nome do contato é substituído.
- Por que é decisão de produto, e não só trabalho: o RF-CONV-014 fala em usar os links "em mensagens" sem separar a mensagem que a automação manda da mensagem que o operador digita à mão, e as duas leituras se defendem. Por isso a pergunta {Q2} existe, e por isso este card não tem dono ainda: fazer o Inbox expandir só o link seria incoerente com o Inbox não expandir o nome.
- Risco hoje: baixo e silencioso. Ninguém recebe erro: o contato recebe a variável escrita, e o operador não fica sabendo que o link que ele colou não vai disparar nada.
- O que fazer: depende da resposta do {Q2}. Se a resposta for que o Inbox precisa expandir, ele passa a expandir as mesmas variáveis do caminho da automação, o nome junto com o link, e aí este card depende também do {AUD-61}. Se a resposta for que o estado de hoje basta, este card fecha como decidido, e o RF-CONV-014 ganha a emenda que restringe a promessa ao caminho da automação.
- Como verificar: depende da resposta do {Q2}, e é escrito quando ela chegar. Escrever o como verificar antes de saber o que se quer seria inventar aceite.
- Aceite (H1): a definir quando o {Q2} for respondido. Card sem aceite não é implementado: enquanto o {Q2} estiver aberto, este card fica na fila como decisão pendente, e não como trabalho pronto para pegar.
- Prioridade: alta, sistêmica. RFs: RF-AUTO-002 (Gatilhos), RNF-003 (confiabilidade). Descoberto em 2026-07-15, no planejamento do {AUD-49}.
- Sintoma: dezoito pontos do produto criam contato; cinco emitem o evento de novo contato, e treze não emitem. Não foram treze esquecimentos aleatórios, foi um padrão: toda vez que alguém escreve um caminho novo que cria contato, tem que lembrar de chamar o motor de eventos à parte, e a disciplina falhou em treze de dezoito vezes.
- Correção de número (2026-07-16), e a lição vale mais que o número: este card afirmava "só quatro emitem" e, na mesma frase, "treze mudos". Os dois não fecham, porque dezoito menos quatro é catorze. O erro veio da varredura que produziu o card: ela procurou pelo nome do emissor do backend e não enxergou o emissor do frontend, que tem outro nome, vive em src/lib/fire-event.ts e manda o evento pela rota pública de eventos, autenticado com a sessão de quem está na tela. Ele cobre a criação de contato pela tela (use-contacts.ts, linha 209) e mais cinco fatos: tag adicionada e removida, agendamento marcado, etapa alterada, oportunidade ganha e perdida. São cinco emissores, não quatro, e agora o conjunto fecha: dezoito pontos, cinco emissores, treze mudos, que são exatamente os doze do {AUD-66} mais o agendamento público do {AUD-57}. O "treze" sempre esteve certo; o "quatro" é que estava errado, e por isso o argumento deste card não muda, ele só passa a ter os números coerentes.
- O quinto emissor foi PROVADO em 2026-07-16, e o defeito que sobra dele mudou de natureza: quatro emissores são do backend e sempre tiveram emissão provada; o quinto, o da tela, era dedução e virou medição, porque o cadastro rápido foi exercitado em produção, respondeu com sucesso e o servidor registrou o evento. O placar de cinco está fechado por medição, e não por leitura de código. O que resta dele é risco latente e não falha viva: a emissão acontece, e falha em silêncio por desenho se um dia for recusada. A função aguarda a chamada e nunca confere o código de retorno da resposta, e aguardar uma chamada não levanta erro quando a resposta é 401, 403 ou 500. Ela tem um aviso no registro do navegador, mas ele só dispara em falha de rede, jamais em recusa da rota. Como a rota de eventos passou a exigir sessão válida e vínculo com a empresa ({AUD-47}), uma recusa faria a emissão sumir sem rastro nenhum, com a tela dizendo que deu certo. O defeito próprio dessa função virou card, o {AUD-85}.
- O que a medição do log permite concluir, e o que ela NÃO permite (2026-07-16): nos últimos trinta dias o registro do serviço tem vinte e quatro emissões do evento de novo contato, e nenhuma delas coincide com um contato realmente nascido. Vinte e três pertencem a uma organização onde nenhum contato nasceu no período, e a vigésima quarta está a mais de duas horas da única criação de contato daquela organização, que ainda por cima veio pelo formulário e não pela tela. São, portanto, emissões sintéticas de teste. Isso prova que a criação de contato pela tela não teve tráfego nenhum no período, e não prova que ela esteja quebrada. O log não confirma nem desmente a emissão do frontend. Quem desempatou foi a medição direta de 2026-07-16, que exercitou a rota e a viu responder com sucesso, com o evento registrado no servidor: a emissão existe. Fica a lição de método, e ela vale além deste card: ausência de tráfego nunca foi ausência de função, e só o teste direto respondeu o que trinta dias de log não responderam. O que se sabe, e basta para este card, é que se ela falhar ninguém fica sabendo. Ler o chamador prova a fiação e nunca o comportamento, e o log tem o limite espelhado: ausência de tráfego não é ausência de função.
- Causa: os webhooks de saída do produto (o canal que avisa sistemas de fora) usam um gatilho no banco, trg_blocob_notify_contacts, e ele está ativo. Correção de 2026-07-16: ele dispara depois de cada inserção, atualização E exclusão de contato, e não "depois de cada inserção" como este card afirmava. Esse caminho é exaustivo por construção na EMISSÃO, impossível de esquecer, porque o banco notifica sozinho. O motor de automação interno não tem o equivalente: depende de cada ponto de código lembrar de chamar a função de emissão de evento, e é exaustivo só por disciplina.
- O modelo que este card manda copiar tem emissão provada e entrega NÃO provada (medido em 2026-07-16, depois que o card já estava publicado): a emissão é exaustiva e provada, com o ouvinte contabilizando 3616 notificações recebidas. A entrega nunca rodou em tráfego real: zero enfileiradas, e o registro de entregas tem seis linhas, todas de 2026-05-09 e 2026-05-10, de teste. A causa é de configuração: das três assinaturas de saída, duas estão desligadas e a única ligada tem a lista de filtros de evento vazia, e o filtro rejeita lista vazia por construção (notify-listener.js, linha 35, retorna falso quando a lista é vazia), então a notificação chega, não casa com ninguém e morre ali.
- A conclusão que este card precisa carregar, porque inverte a lição: "nunca perdeu um" é indistinguível de "nunca entregou nenhum", porque os dois produzem exatamente o mesmo registro vazio. O modelo não está provado no todo, só na metade. E o próprio ouvinte confessa no cabeçalho (linhas 11 e 12) que a notificação do banco é dispare e esqueça, e que evento em trânsito se perde se o processo cair. Copiar a EMISSÃO deste modelo é sólido e continua sendo a recomendação; copiar a ENTREGA dele é copiar algo que nunca foi exercitado, e a decisão do council precisa saber disso antes de escolher.
- DECISÃO TOMADA (council de 2026-07-16, três personas, convergiu): dar ao motor de automação exaustividade por construção para o fato "contato criado", por meio de um gatilho no banco, consumido pela fila de trabalho que já existe. Este card deixa de pedir council, porque o council rodou; o que resta é executar a sequência definida no fim deste card.
- Por que a alternativa barata foi REPROVADA, e foi por medição e não por gosto: emitir o evento dentro do ajudante que procura ou cria o contato (findOrCreateContact) parece o conserto de uma linha só, e cobriria oito caminhos de tráfego ZERO e nenhum dos três que têm tráfego vivo. Agendamento (876), formulário (1921) e livechat (2347) não usam o ajudante: cada um reimplementa à mão o procura e insere. Os dois piores mudos também não passam por ele, a interface pública de ingestão (ingest-contacts.js, linha 435) e o cron de leads (cron-meta-leads-sync.js, linha 182). Conserto que não toca nenhum caminho com tráfego não é conserto barato, é conserto nenhum.
- Por que o argumento contra o gatilho caiu: dizia-se que o gatilho no banco perde o pacote rico e o filtro por origem. A função que decide se o evento casa com a configuração do gatilho (webhook-index.js, linhas 6606 a 6626) não tem ramo para contato criado e cai no retorno verdadeiro do fim, e filtro por origem nesse gatilho não existe no código. A perda é teórica e mensurável em zero. O defeito próprio dessa função é o {AUD-81}.
- Consumo pela fila que já existe, e não por escuta direta no banco: o ouvinte roda no processo de saída e o emissor de eventos roda no processo do webhook, então chamar em processo é impossível hoje. A fila resolve isso e dá durabilidade DEPOIS que o evento é enfileirado, que é o que a notificação do banco não dá (notify-listener.js, linhas 11 e 12, confessa que é dispare e esqueça). Correção pela medição da implementação (2026-07-17), e ela inverte a frase que este card trazia: a ponte EXIGE um endpoint interno novo, o POST /internal/fire-event no webhook, porque o consumidor da fila vive no processo do worker de saída e o emissor de eventos vive no processo do webhook, e sem o endpoint o webhook teria que ganhar dependência da fila e do Redis mais o rebuild da imagem. O card afirmava "não entra rota nova de HTTP", e estava errado nesse detalhe: entra, sim, um endpoint máquina a máquina, fail closed nos dois eixos (segredo compartilhado no cabeçalho e vínculo ao laço de retorno local, fora do nginx). Ele NÃO reabre o {AUD-47} porque não é superfície de usuário: o {AUD-47} trata do perímetro autenticado das rotas de usuário, e este endpoint não é rota de usuário, é encanamento entre dois processos. Lição da casa, de novo: o card mente, a medição corrige.
- Limite honesto do parágrafo acima, registrado para não virar folclore: a fila torna durável o trecho DEPOIS do enfileiramento, e o salto do banco até o ouvinte continua sendo dispare e esqueça. Evento notificado com o ouvinte fora do ar se perde, e fila nenhuma conserta isso. A fila encurta a janela, não a elimina; fechá-la de vez exigiria caixa de saída no banco, e isso NÃO está decidido aqui. Quem ler "a fila resolve a não durabilidade" sem esta ressalva vai medir errado o que foi entregue.
- Canal próprio (automation_event), e não assinar o canal de saída existente: juntar os dois acopla o barramento do cliente ao motor interno e traz junto o contato atualizado, que é exatamente o vetor de risco sobre os 1503 contatos descrito no acoplamento com o {AUD-80}.
- LIMITAÇÃO DECLARADA, que não pode sumir deste texto: isto resolve o "contato criado" e só ele. Tag adicionada, etapa alterada, oportunidade ganha, oportunidade perdida e agendamento marcado NÃO têm linha em contacts para gatilhar, e continuam exaustivos por disciplina depois desta entrega. Quem vender esta decisão como "agora tudo é por construção" está errado, e o RF-AUTO-002 segue exposto nos outros fatos.
- Dissidência registrada (a persona cética, e ela não foi vencida no mérito): o tráfego vivo é de doze contatos por mês, a Hiit Fitwear não tem automação nenhuma montada, e a única que estrearia com o conserto é o "Welcome + Tag", que o {AUD-75} prova quebrado. Pelo impacto medido isto não é P0. Medição de 2026-07-16, na mesma sessão da F2, fecha esse impacto com números e corrige só a honestidade da urgência declarada, não a decisão: o tenant piloto tem zero automações montadas, em nenhum estado, e as vinte e uma execuções registradas em toda a história do produto pertencem cem por cento à empresa de teste, ou seja, nenhum contato real é alcançável hoje por este caminho. Por que se decidiu fazer assim mesmo: o RF-AUTO-002 é lei publicada e está violado na cláusula "nenhum gatilho que valha só para parte dos caminhos por onde o fato acontece"; reduzir o H1 deste card para caber na opção barata seria baixar a promessa para caber no que é fácil, e a casa proíbe isso.
- Sequência obrigatória, e a ordem é parte da decisão e não sugestão. Cada fase é entregável e testável sozinha, e nenhuma delas depende de decisão nova para começar.
- F0, medir antes de tudo: CUMPRIDA em 2026-07-16. A rota de eventos do cadastro rápido foi exercitada em produção, respondeu com sucesso e o servidor registrou o evento. O placar de cinco emissores está fechado por medição, e não por leitura de código: o quinto emissor emite de verdade. O buraco que sobra é o do {AUD-85}, e ele mudou de natureza, porque a emissão está provada e o que resta é a cegueira a uma recusa futura.
- F1, chave de idempotência no banco ({AUD-82}): CUMPRIDA em 2026-07-16. Ela tornou a migração possível sem janela de mensagem duplicada para o contato real, e com isso a F3 deixa de estar PROIBIDA pela falta da chave. É só isso que mudou: a F3 continua atrás da F2 e da F2.bis, que são as salvaguardas e não foram entregues. E a chave protege contra o mesmo fato virar efeito duplicado, e não dá durabilidade ao salto do banco até o ouvinte, que segue sem garantia.
- F2, salvaguardas, todas antes do gatilho: CUMPRIDA em 2026-07-16, mergeada em produção, com os três gates verdes de planejamento, qa e revisão de código. As quatro nascem restritivas: a chave geral de desligamento nasce desligada e editável na tela, a lista de permissão por empresa nasce só com a empresa de teste, a lista de permissão por tipo de evento aceita só contato criado, e o teto de disparo por empresa por janela abre em sessenta disparos por hora corrida. As quatro são conferidas no executor de passo, e a medição provou que esse é o único ponto por onde todos os caminhos passam: o qa exercitou inclusive o caminho que retoma uma execução agendada, que não passa pelo disparador comum, e a guarda pegou também ali. O teto de sessenta tem fonte, e ela é medida: a maior hora orgânica já registrada em qualquer empresa foi vinte e dois disparos; sessenta dá folga de quase três vezes esse pico, e ainda assim trava, em cinco por cento do valor, o pico artificial de uma importação em massa, que é exatamente o cenário que a guarda existe para conter. Duas correções aconteceram durante a fatia, e as duas eram guarda que não guardava, o que vale registrar como lição: primeiro, o teto se contornava sozinho, em silêncio, quando a própria medição dele falhava, e passou a negar por padrão, com um motivo nomeado, quando isso acontece; segundo, só a chave geral era lida sem cache, as outras três demoravam até um minuto para valer, o que numa lista de permissão é a promessa falhando exatamente no momento em que ela importa, e agora as quatro leem sem cache. O que a entrega PERDE, e foi decidido: a chave nascer desligada desliga a automação de quem já a usava, e quem já a usava é só a empresa de teste, porque o tenant piloto tem zero automações montadas, em nenhum estado, e todas as execuções da história inteira são da empresa de teste, então nenhum contato real é alcançado. Fica declarada a restrição que vale para a F3, e ela já é parte desta entrega: o gatilho do banco entra pelo emissor de eventos e nunca cria execução diretamente, porque criar direto contornaria por construção o teto e a lista de evento, e quebraria a premissa de ponto único de criação que a chave de idempotência da F1 pressupõe.
- F2.bis, o {AUD-83} e o {AUD-84} entram ANTES do gatilho, e cresceram em 2026-07-16: não é um emissor, são quatro pontos que despacham whatsapp, e nenhum decide pelo estado real do canal. A crença "a Hiit não tem whatsapp ligado, logo não sai mensagem" é FALSA, e alguém vai decidir em cima dela, inclusive a decisão deste card. A raiz é a ausência de um lugar único que responda se a empresa tem whatsapp utilizável, e é ele que a F2.bis entrega: consertar os quatro pontos um a um é ser exaustivo por disciplina outra vez, que é exatamente o vício que este card inteiro existe para matar.
- F3, o gatilho no banco mais o consumo pela fila: CUMPRIDA em 2026-07-17, mergeada em produção (merge b6ca1f1), com os três gates verdes de planejamento, qa e revisão de código. O desenho entregue, peça a peça: um gatilho depois de cada inserção em contacts notifica um canal próprio, automation_event, separado do canal de saída; o ouvinte que roda no processo de saída passou a escutar esse canal também (a reconexão reemite os dois canais, provado pelo C1) e enfileira na fila de trabalho mcrm-automation-events; um consumidor novo, no mesmo processo de saída, chama o emissor de eventos por HTTP no endpoint interno POST /internal/fire-event do webhook, fail closed nos dois eixos (500 se o segredo falta no ambiente, 401 se o segredo do cabeçalho está errado, preso ao laço de retorno local e fora do nginx), e o webhook chama o emissor de eventos de sempre, que nunca cria execução direto. A chave de idempotência, contato criado mais o identificador do contato, é função pura do identificador e colide por construção com os emissores antigos, então conviver com eles não duplica: o qa provou (T2) duas execuções e não quatro para um contato criado ao mesmo tempo pela tela e pelo gatilho. O caminho novo passa por todas as quatro salvaguardas da F2 (provado, T3 e T6). A durabilidade é garantida DEPOIS do enfileiramento (T4a: o trabalho sobreviveu a quatro quedas e a execução nasceu uma vez só); o salto do gatilho até o ouvinte segue dispare e esqueça (T4b provado: o ouvinte fora do ar no instante da inserção perde o evento, esperado e documentado). Ela shipou DORMENTE (a chave geral estava desligada no merge, e ligá-la nunca foi parte dele); em 2026-07-17, com GO do Wladimir e depois do {AUD-100} resolvido, a chave foi LIGADA sob observação, e a estreia foi provada por um contato de prova cujo "Welcome + Tag" completou aplicando a tag. O qa passou de T1 a T6 mais o C1 da reconexão.
- F4, remover os emissores antigos, um a um, medindo, e só depois da F3 provada: CUMPRIDA em 2026-07-17. Os cinco emissores antigos de contato criado foram removidos, cada um com o seu teste provando que o caminho dele continua disparando automação só pelo gatilho: o do email por IMAP (fetcher.js), o do WhatsApp Evolution de entrada, o do formulário e lead genérico, o do Meta Lead Ads e o da tela (cadastro rápido e criar contato). Contagem final no que roda em produção: ZERO emissores de contato criado fora do trilho novo. Correção de composição do card, registrada por honestidade: o quinto emissor real era o fetcher do IMAP, e a interface pública de ingestão (ingest-contacts) NÃO emitia nada, só gravava auditoria; o card tinha errado a composição, e o conjunto agora fecha por medição, três no webhook mais um no IMAP mais um na tela, cinco de cinco. No Meta Lead Ads a remoção é também correção de semântica: ele emitia contato criado até quando o lead casava um contato que já existia (atualização, não inserção), e disparar criado para quem não foi criado é o fato errado; a automação específica do formulário do Meta segue intacta, mantida de propósito. O formulário e a tela foram provados por exercício real depois da remoção (webhook de lead e cadastro rápido registrados em log): uma execução por automação e por contato, agora só pelo gatilho.
- FECHAMENTO do {AUD-65} (2026-07-17): com a F3 e a F4 entregues, o H1 fechou, e a prova é comportamental. Um caminho de criação de contato SEM nenhuma chamada de emissão no código dispara automação (T1 da F3, uma inserção direta no banco gerou execução com os passos rodando), e os pontos hoje mudos migraram para o desenho novo em vez de ganhar N correções pontuais. Dois limites que este fechamento NÃO cobre, e precisam ficar no texto senão o fechado mente: (a) só o fato contato criado é exaustivo por construção; tag adicionada, etapa alterada, oportunidade, agendamento e os demais seguem exaustivos por disciplina, e o {AUD-85} continua aberto para eles; (b) durabilidade: o salto do gatilho até o ouvinte é dispare e esqueça, e a F4, ao remover os cinco emissores antigos, tirou o cinto e suspensório que a convivência dava, então a janela de perda deixou de ter redundância, e é isso que faz nascer o card de caixa de saída, o {AUD-99}, exatamente como o gate da F3 previu (seção 8, condição c).
- O {AUD-75} entra antes ou junto da F3, senão o primeiro resultado visível deste conserto é uma automação quebrada estreando para o cliente.
- Pré-requisito que independe da opção escolhida ({AUD-82}): a tabela de execuções de automação não tem chave de idempotência nenhuma, e o RNF-003 exige que a idempotência evite efeito duplicado. Com a chave, ligar um emissor novo convivendo com os antigos é inofensivo; sem ela, toda migração de emissão tem uma janela de mensagem duplicada para o contato real. Decidir o {AUD-65} sem resolver o {AUD-82} antes é escolher a janela.
- Acoplamento com o {AUD-80}, e ele é sério: o conserto do {AUD-80} é uma atualização em massa nos mesmos 1503 contatos da Hiit Fitwear, e o gatilho citado acima já dispara em atualização, não só em inserção. Se as duas fatias se cruzarem na mesma janela sem uma lista de permissão por tipo de evento, o card que conserta o nome vira o card que dispara automação para os 1438 contatos reais que têm telefone. As duas fatias são incompatíveis na mesma janela e a ordem entre elas precisa ser decidida, não descoberta.
- Por que decidir antes: se os doze cards do {AUD-66} forem corrigidos um a um sem resolver a raiz, a casa paga doze vezes um conserto que o desenho certo faria uma vez, e o décimo nono caminho que alguém escrever amanhã nasce mudo de novo.
- Como verificar: a decisão de arquitetura está registrada neste card (council de 2026-07-16), e a prova de pronto é comportamental, não documental. Escrever um caminho novo de criação de contato SEM nenhuma chamada de emissão no código dele e confirmar execução de automação registrada para o contato nascido por ali; e confirmar que os treze pontos hoje mudos passam a disparar sem ganhar treze chamadas.
- Aceite (H1): Dado a decisão de arquitetura tomada, Quando um novo caminho de criação de contato é escrito depois dela, Então ele dispara a automação de novo contato sem exigir lembrete manual de quem o escreveu, E os doze pontos hoje mudos ({AUD-66}) migram para o novo desenho em vez de ganhar doze correções pontuais.
- Prioridade: alta para os dois primeiros (tráfego real hoje), média para os demais. RF: RF-AUTO-002 (Gatilhos). Descoberto em 2026-07-15, no planejamento do {AUD-49}. Depende da decisão do {AUD-65}.
- Sintoma: doze caminhos criam contato do jeito certo e não chamam o motor de eventos, então a automação de novo contato nunca dispara neles. Nominal: livechat (webchat público), Instagram (mensagem direta), comentário no Instagram, Messenger, comentário no Facebook, SMS, WhatsApp Meta Cloud, importação de CSV, tela de oportunidade (criar contato pela tela de funil), API de ingestão, cron de sincronização do Meta Leads, e o formulário público. O agendamento público é o irmão mais grave da mesma doença, e já tem card próprio, o {AUD-57}.
- Por que a prioridade é nominal e não uniforme: dos doze, dois têm tráfego real medido nos últimos trinta dias, livechat (seis contatos) e formulário (três contatos); os demais não tiveram contato algum no mesmo período. Priorizar livechat e depois formulário, se a decisão do {AUD-65} não estiver pronta a tempo de corrigir todos de uma vez.
- O que fazer: o {AUD-65} DECIDIU pelo desenho exaustivo por construção (council de 2026-07-16), então este card se resolve junto com a fase F3 daquele card, sem correção ponto a ponto. A correção caminho a caminho, chamando o motor de eventos com o campo e a forma certos, deixa de ser o plano e passa a ser contingência: só se justifica se a F3 for adiada, e nesse caso começa por livechat e formulário, que são os dois com tráfego real.
- Como verificar: com uma automação ativa no gatilho de novo contato, criar um contato por cada um dos doze caminhos e confirmar execução registrada para cada um.
- Aceite (H1): Dado uma automação ativa no gatilho de novo contato, Quando um contato nasce por qualquer um dos doze caminhos listados, Então a automação executa E a execução fica registrada, para todos os doze.
- Prioridade: média-alta, defeito real pré-existente. RF: RF-CAPT-004 (webhook genérico). Descoberto em 2026-07-15, no qa do {AUD-49}. Confirmado pré-existente, idêntico no commit-base 109857f, não introduzido por esta fatia.
- Sintoma: um lead que traz o campo de mensagem quebra com erro quinhentos, mesmo depois de o contato já ter sido criado. Quem envia o lead recebe erro mesmo quando metade do trabalho já aconteceu.
- Causa: a chamada que grava a mensagem usa um tratamento de erro encadeado (catch) num resultado que não é uma Promise de verdade, e por isso o encadeamento não é uma função válida ali (TypeError: catch is not a function). O objeto que a biblioteca de acesso ao banco devolve é thenable, tem then e por isso await funciona, mas não é Promise de verdade e não tem catch: encadear catch nele lança TypeError no instante em que a linha roda.
- O que fazer: corrigir a chamada para tratar o erro da forma que a biblioteca espera, sem deixar o contato já criado às cegas quanto ao resultado da mensagem.
- Como verificar: enviar um lead com o campo de mensagem preenchido pelo webhook e confirmar resposta de sucesso, com o contato e a mensagem gravados.
- Aceite (H1): Dado um lead enviado pelo webhook com o campo de mensagem preenchido, Quando o webhook processa o envio, Então responde sucesso, E o contato e a mensagem ficam gravados, sem erro quinhentos.
- O defeito era maior do que o card sabia quando nasceu: o TypeError na linha da nota pulava a chamada seguinte do motor de eventos, então lead com mensagem não era só erro quinhentos, era também zero disparo de automação. Provado por controle antes do conserto: lead com mensagem, erro quinhentos, contato criado, zero nota gravada, zero execução; lead sem mensagem, sucesso, duas execuções. Depois do conserto, provado em produção: lead com mensagem, sucesso, nota gravada, evento contact.created registrado, duas execuções, e a nota aparece na tela do contato, aba Atividade, nos dois temas, com o rótulo Nota em português.
- Entregue em 2026-07-15, commits aa06df1 e 42237db, um por causa, path específico por card, merge aaa0c29, com o webhook reiniciado e a prova rodada em produção. Gates: plan APPROVED, qa PASS, review APPROVED, zero Critical, checagem de antirregressão limpa.
- Consequência para o {AUD-49}: o {AUD-49} foi mergeado anunciando que o webhook público de lead passa a disparar a automação, e o gate de qa daquela fatia passou porque o teste exercitou só o lead sem mensagem. Por cerca de duas horas o marcador de concluído do {AUD-49} foi verdade parcial, porque o gatilho não disparava para lead com mensagem, e mensagem é um dos campos mais comuns de formulário. O qa desta fatia revalidou o {AUD-49} nos dois ramos, com e sem mensagem, e agora o marcador de concluído dele é verdade de fato. Nota registrada no próprio card {AUD-49}.
- Prioridade: alta, mesma família da Onda AUD, tela ou registro que finge sucesso. RFs: RF-AUTO-044 (honestidade do registro de execução, requisito escrito em 2026-07-16 por causa deste card), RF-AUTO-003 (Ações). Descoberto em 2026-07-15, no qa do {AUD-49}; replanejado em 2026-07-16, quando o recorte cresceu do sintoma para a raiz. A referência ao RF-CONV-054 saiu daqui em 2026-07-16: aquele requisito trata da mensagem e o gatilho do H1 dele é o operador tentando enviar pela tela, então ele não reprova nada deste card, onde quem roda é o motor sozinho e metade dos casos não é mensagem. Era a mesma classe de erro do {AUD-70}, rastreabilidade apontando para requisito que não reprova o defeito.
- Sintoma: a ação "adicionar tag" de uma automação grava o passo como concluído e não aplica tag nenhuma no contato. A ação de enviar mensagem por WhatsApp grava concluído sem canal conectado, sem telefone e sem ter enviado nada. O planejamento de 2026-07-16 mediu o alcance real: em toda a história do produto os passos de automação registraram dezoito vezes concluído, uma vez em execução, e nenhuma vez falha ou ignorado. Um campo de estado que só assume um valor não é estado, é enfeite.
- Causa (revista em 2026-07-16, e é mais funda do que o card supunha): nenhum handler grava o próprio estado. Quem grava é o executor, num ponto único, a partir da premissa de que não ter havido exceção significa ter dado certo. Somado a isso, nada no motor produz exceção: o cliente de banco devolve o erro em vez de lançar, e ninguém lê esse erro; a chamada de rede também não lança em resposta de erro do destino. São dois silenciadores independentes, e nenhum dos dois sozinho explica o defeito. O resultado é que zero de vinte e uma rotas de ação conferem o próprio efeito antes de dizer concluído. O nome da tag guardado no lugar do identificador é sintoma de um defeito à parte, do modelo pronto, e virou o {AUD-75}.
- O que fazer (decidido no gate de plano de 2026-07-16, e substitui o que este card prescrevia antes): mudar o contrato entre o executor e as vinte e uma rotas, para que cada rota devolva um desfecho explícito (concluído, ignorado com motivo, ou falha com erro) em vez de não devolver nada. Morre o concluído incondicional do ponto único; o estado passa a ser derivado do que a rota afirma, e o padrão do contrato passa a ser falha, não sucesso. Ler o erro do banco dentro das rotas e conferir a resposta das chamadas de rede, sem ligar lançamento de exceção global no cliente compartilhado, que serve o produto inteiro e viraria camada nova para consertar um motor. Gravar o motivo e o erro nos campos de entrada e saída do passo, que já existem no banco e nunca foram escritos. Sem migração, sem tela nova. O que este card recusa por escrito: resolver o nome da tag em tempo de execução e criar a tag se não existir, que era o conserto prescrito aqui até 2026-07-16. Ele faria o sintoma sumir e deixaria as outras vinte rotas mentindo, e ainda apagaria a única reprova natural que existe hoje em produção. É apagar o lixo na origem e deixar a tela mentindo. Quem conserta o modelo é o {AUD-75}, e vem depois.
- Como verificar: reprova antes de tocar em código, com o gatilho real (criar contato pela interface de programação na empresa de teste), registrando o identificador da execução e provando os dois passos concluídos com zero efeito. Depois do conserto, três provas, e as duas últimas não são opcionais: o passo de configuração inválida fica em falha e a execução para; uma automação legítima, com o identificador de tag real, termina com todos os passos concluídos e o efeito existindo de verdade no banco (é o que prova que a fatia não transformou automação boa em falha); e uma automação com mensagem numa empresa sem canal, seguida de outro passo, deixa a mensagem ignorada, executa o passo seguinte e termina a execução concluída. Smoke visual real: abrir o histórico da automação e ver a execução vermelha da primeira e a verde da segunda.
- Aceite (H1): é o H1 do RF-AUTO-044, e não uma paráfrase dele: Dado uma automação ativa cujo passo não produz o efeito pretendido, seja por configuração inválida, seja por pré-condição legitimamente ausente, Quando a automação roda para um contato, Então nenhum desses passos fica registrado como concluído, E o de configuração inválida fica em falha com o erro nomeado e a automação para, E o sem pré-condição fica ignorado com o motivo nomeado e a automação segue; E, Dado uma automação cujos passos têm efeito, Quando ela roda, Então os passos ficam concluídos e o efeito existe de verdade no banco, E a execução inteira não fica marcada como falha por causa de passo ignorado. A última cláusula é o aceite que reprova o excesso de falha: um H1 que só olhasse para um lado do erro deixaria passar em verde a correção que quebra automação legítima.
- Entregue em 2026-07-16, commit 67224ec, merge 06e9724, path específico webhook-index.js, com o webhook reiniciado e a prova rodada em produção. Zero migração, zero tela nova, zero DDL. Gates: plan APPROVED, qa PASS, review APPROVED.
- Provas do qa (efeito real no banco, não só o próprio registro do passo): reprova antes, sem reverter código, usando dado histórico real (seis execuções antigas do workflow "Welcome + Tag" registravam concluído sem a tag "novo" jamais ter existido na empresa); anti-falso-positivo (tag real aplicada, linha real em contact_tags fora do próprio registro do passo, e o passo seguinte roda); dois casos de ignorado que segue (contato sem telefone, empresa sem canal de WhatsApp), cada um com o motivo nomeado e o passo seguinte rodando de fato; configuração inválida (identificador de tag ausente) fica em falha e a automação para, sem o passo seguinte ganhar linha; ação que o motor não executa (nome que a tela oferece e o motor não implementa) fica em falha e a automação para; remover uma tag que o contato nunca teve permanece concluído, porque zero linhas apagadas é o estado desejado alcançado.
- Achado do qa fora do escopo desta fatia, correto pelo H1 e não bloqueante: rodar o evento real contra os dois workflows ativos da organização de teste (dogfooding da própria Modulareasy) mostrou o "Follow-up automático" sem mudança de comportamento, e o "Welcome + Tag" passando a falhar e parar no primeiro passo, porque o passo de adicionar tag daquele workflow está configurado com o nome da tag em vez do identificador, e nunca resolveu para uma tag real. Auditado nas seis organizações do banco por critério, não por amostra: o padrão existe num único workflow, este; a Hiit, tenant piloto, tem zero workflows; zero exposição a cliente pagante. Virou o {AUD-78}.
- Achado do review, fora do escopo desta fatia, anexado ao {AUD-69} já existente: a superfície de dado pessoal em log e erro cresceu de um ponto de escrita para cerca de doze, sem filtro.
- Confirmação visual (2026-07-16, sessão viva em produção, modo claro e modo escuro): o Dashboard de Automações mostra a execução do "Welcome + Tag" como Falhou, em vermelho, com o erro nomeado (Step add_tag failed: add_tag: configuracao invalida, tag_id ausente), e a Taxa de sucesso (30d) passa a mostrar 42,9% (6 de 14), honesto contra os 100% falsos de antes. O mesmo smoke achou dois defeitos novos, adiante neste roadmap em {AUD-79} e {AUD-80}.
- Prioridade: média, achado do code review (I1), sem caminho real de exploração hoje. Aproxima-se do RNF-002 (segredos fora de log) e do RNF-006 (observabilidade), embora nenhum dos dois nomeie hoje dado de contato em log; decisão de emendar um dos dois fica fora do escopo deste card. Descoberto em 2026-07-15, no review do {AUD-49}.
- Sintoma: a guarda que passou a registrar evento malformado no log ({AUD-49}) serializa o evento inteiro, e o pacote de dados de um evento pode carregar identificador, e-mail, telefone ou mensagem do contato.
- Risco hoje: quase inalcançável, porque os dois chamadores atuais do motor de eventos são bem formados e nunca acionam esta guarda. O risco cresce porque os próximos cards desta família ({AUD-65}, {AUD-66}, {AUD-57}) vão chamar a mesma função direto, de mais lugares.
- O que fazer: logar só as chaves presentes no evento malformado, nunca os valores.
- Como verificar: forçar um evento malformado em harness isolado e confirmar que o log mostra as chaves e não os valores.
- Aceite (H1): Dado um evento malformado chegando à guarda, Quando ela registra o log, Então o log mostra quais chaves vieram, E nenhum valor de dado pessoal aparece no log.
- Adendo do review do {AUD-68} (2026-07-16, achado I1, fora do escopo daquela fatia, anexado aqui por já existir card para a classe): a superfície de dado pessoal em log e erro cresceu de um ponto de escrita para cerca de doze (onze rotas do executor mais o novo log central do passo), cada uma propagando a mensagem de erro crua do banco sem filtro. Não é regressão, e nenhuma rota interpola campo de contato direto na mensagem, mas a área que este card cobre ficou maior: o mesmo risco descrito acima, log sem filtro de dado pessoal, agora em mais lugares.
- Prioridade: baixa, correção documental. RFs: RF-CAPT-004 (a captura, correto), RF-LEAD (gestão de contato, o que o card {AUD-49} aponta hoje, errado). Descoberto em 2026-07-15, no planejamento do {AUD-49}.
- Sintoma: o card {AUD-49} lista RF-LEAD como requisito coberto. RF-LEAD é gestão de contato, o que fazer com o contato depois de criado, não captura. Quem recebe o lead pelo webhook é o RF-CAPT-004.
- Por que importa, além da exatidão: o RF-CAPT-004 não reprova o defeito que o {AUD-49} corrigiu, porque o H1 dele exige só que o lead vire contato e que envios malformados sejam rejeitados, e o contato sempre foi criado. O silêncio da automação nunca violou requisito nenhum, porque nenhum requisito de captura promete disparo de automação. É a mesma classe de furo que a regra de falseabilidade existe para fechar: requisito que não reprova nada não gateia nada.
- O que fazer: trocar a referência do {AUD-49} de RF-LEAD para RF-CAPT-004, e registrar no RF-AUTO-002 a exigência explícita de que o gatilho de novo contato vale por todos os caminhos de criação de contato, não só por amostra, para que este tipo de furo passe a ser coberto por um requisito que efetivamente reprova.
- Como verificar: a emenda do RF-AUTO-002 nomeia a exigência "por todos os caminhos de criação de contato"; o card {AUD-49} referencia RF-CAPT-004 no lugar de RF-LEAD.
- Aceite (H1): Dado o RF-AUTO-002 emendado, Quando um caminho de criação de contato não dispara a automação, Então esse requisito é violado por fato verificável, e não apenas por impressão, E o {AUD-49} referencia o requisito de captura correto.
- Prioridade: P1 latente, não P0 ativo. RFs: RF-CONV-005 (Messenger), RF-CONV-006 (Instagram). Descoberto em 2026-07-15, na mesma varredura do {AUD-67}. Último código publicado antes deste card era o {AUD-70}.
- Sintoma: nas linhas que processam mensagem direta do Instagram e do Messenger, o bloco finally liberava o lock de conversa encadeando catch num resultado que não é uma Promise, a mesma classe de defeito do {AUD-67} (o objeto que a biblioteca de acesso ao banco devolve é thenable, não é Promise de verdade, não tem catch). O TypeError no finally impedia o release do lock, mascarava a exceção original do try escondendo o motivo real de qualquer falha ali, e impedia a mensagem do cliente de entrar no inbox.
- Causa: duas ocorrências, por volta das linhas 2658 e 2839, do commit 35df920a (12/05), cada uma independente da outra e independente da linha do {AUD-67}, do commit bba00905 (19/04). Não é uma raiz com três sintomas: são três erros independentes do mesmo tipo, em pontos diferentes do arquivo, cada um nascido no seu próprio commit. Corrigir um não corrige o outro, por isso viraram dois cards na mesma branch.
- Risco hoje: P1 latente, não P0 ativo. O caminho nunca executou em produção, pg_locks mostra zero locks dessa família e todas as conversas estão com status aberto, coerente com o {AUD-42} (a conexão com a Meta está morta). O defeito acende na segunda mensagem de uma conversa já respondida, no dia em que o {AUD-42} for consertado e a Meta voltar a entregar mensagem de verdade.
- O que fazer: corrigir a chamada de release do lock para tratar o erro da forma que a biblioteca espera, do mesmo jeito que o {AUD-67}, nos dois pontos.
- Como verificar: com controle, provar que o baseline reprova (erro quinhentos, mensagem não gravada, lock preso) e que depois do conserto responde sucesso, com a mensagem gravada e sem a exceção original mascarada.
- Aceite (H1): Dado uma mensagem do Instagram ou do Messenger chegando ao processamento, Quando o release do lock no finally executa, Então não lança TypeError, E a mensagem fica gravada e visível no inbox, E uma falha real do try, se houver, aparece sem ser mascarada pelo finally.
- Limite honesto que este card declara: este card mata o TypeError do release, não a possibilidade de o lock ficar preso por outra causa. O {AUD-72} documenta um jeito diferente e pré-existente de o lock ficar preso, achado ao medir depois deste conserto, e este card não promete que o lock nunca fica preso.
- Entregue em 2026-07-15, commits aa06df1 e 42237db, mesma branch do {AUD-67}, path específico por card, merge aaa0c29. Gates: plan APPROVED, qa PASS, review APPROVED. Já gateado pelo RF-CONV-005 e RF-CONV-006 (a mensagem aparece no inbox), sem necessidade de emenda ao DRS. Smoke visual do inbox não feito nesta entrega, porque o caminho Meta está morto pelo {AUD-42}; a prova foi por banco, log e mecanismo isolado, não por navegação real na tela.
- Prioridade: P1, achado do qa medindo depois do {AUD-71}. RFs: RF-CONV-005, RF-CONV-006, RNF-003 (confiabilidade). Descoberto em 2026-07-15, no qa do {AUD-71}. Último código publicado antes deste card era o {AUD-71}.
- Sintoma: depois do conserto do {AUD-71}, pg_locks mostrou um lock, não zero. Não é o TypeError, que já morreu: try_advisory_lock_conversation usa pg_try_advisory_lock de sessão, não de transação, e o PostgREST usa pool de conexão persistente. O release cai numa conexão diferente da que adquiriu o lock, e a conexão original volta ao pool com estado ocioso e o lock ainda concedido.
- Evidência: reproduzido uma vez em uma tentativa, sem nada sintético, com o mecanismo isolado.
- Por que não é regressão: é defeito pré-existente de arquitetura, lock consultivo de sessão combinado com pool de conexão, desde o commit 35df920a. O gate do {AUD-71} declarou este ponto fora do escopo antes do teste rodar, não depois, por conveniência retroativa. É por isso que o {AUD-71} não promete que o lock nunca fica preso.
- Risco hoje: o mesmo do {AUD-71}, dormente enquanto o {AUD-42} mantiver a conexão Meta morta, acende junto com ele.
- O que fazer: trocar o lock de sessão por lock de transação (pg_try_advisory_xact_lock), que libera sozinho no fim da transação independentemente de qual conexão do pool o segurou, ou mudar o release para não depender de reaproveitar a mesma conexão. Decisão de arquitetura, não fatia isolada.
- Como verificar: adquirir o lock, forçar a devolução da conexão ao pool antes do release explícito, e confirmar que o lock não fica preso mesmo assim.
- Aceite (H1): Dado um lock de conversa adquirido, Quando a conexão que o adquiriu volta ao pool antes do release explícito, Então o lock não fica preso indefinidamente, E uma nova tentativa de adquiri-lo mais tarde consegue.
- Prioridade: média, pré-existente. RF: RF-UX-004 (acessibilidade AA). Descoberto em 2026-07-15, no qa do {AUD-67} e do {AUD-71}.
- Sintoma: medido em produção, no modo claro, compondo o valor alpha da cor sobre o fundo: contraste de 2,71 para 1 num texto de 10px (rgb(147,157,175) sobre rgb(254,254,255)). O AA exige 4,5 para 1 em texto pequeno.
- Pré-existente, não introduzido pelo {AUD-51}: o diff daquela fatia só removeu a classe uppercase; a cor (token text-muted-foreground com 70% de opacidade) e o tamanho já eram esses quando o selo exibia NOTE em caixa alta.
- Por que é violação de requisito, não capricho: o RF-UX-004 é requisito publicado no DRS, não preferência de estilo. Contraste abaixo do exigido reprova o requisito por fato medido, não por impressão.
- O que fazer: aumentar o contraste do rótulo, cor mais escura no claro e mais clara no escuro, até atingir 4,5 para 1, e verificar se o mesmo token ou tamanho se repete em outros selos do produto antes de corrigir por amostra.
- Como verificar: medir o contraste renderizado do rótulo em produção, no claro e no escuro, e confirmar 4,5 para 1 ou mais; varrer os demais selos que usam o mesmo token.
- Aceite (H1): Dado o rótulo da linha do tempo do contato renderizado, Quando o contraste entre o texto e o fundo é medido, Então o resultado é 4,5 para 1 ou mais, tanto no claro quanto no escuro, E qualquer outro selo do produto que usa o mesmo token de cor e tamanho também passa a atender, E nenhuma varredura ficou por amostra.
Achados do planejamento do {AUD-68} (2026-07-16)
Os quatro cards abaixo nasceram da varredura por critério das vinte e uma rotas de ação do motor de automação, feita no planejamento do {AUD-68}. Todos vêm DEPOIS do {AUD-68}, e a ordem não é preferência: é o {AUD-68} que torna estes visíveis, porque com o desfecho padrão virando falha eles gritam na primeira execução. Consertar qualquer um deles antes apagaria a única reprova natural que existe hoje em produção. Os quatro compartilham a raiz que o {AUD-68} não cobre: o {AUD-68} torna honesto o registro do que o passo tentou, e não do que o passo deveria ser.
- Prioridade: alta. É o achado maior do planejamento do {AUD-68}. RFs: RF-AUTO-044 (regra de honestidade da lista de ações), RF-AUTO-003 (Ações). Descoberto em 2026-07-16.
- Sintoma: a lista de ações do editor oferece "mover etapa" (move_stage) e "atualizar status da oportunidade" (update_opportunity_status). O motor não tem rota para nenhuma das duas: as duas caem na rota padrão, que registra "ação desconhecida" e reporta o passo como concluído. O painel de configuração trata "mover etapa" como ação completa, com escolha de funil e de etapa. O usuário configura, salva, ativa, vê verde, e nada acontece, para sempre.
- A ironia que fecha o diagnóstico: a ação que o motor executa de verdade, mover a oportunidade de etapa no funil (move_pipeline_stage), não é oferecida na tela. A que funciona está inalcançável e a que o usuário recebe é a quebrada.
- Causa: a lista de ações da tela e o conjunto de rotas do motor são duas listas mantidas à mão, e nada reconcilia uma com a outra. Exaustivas por disciplina, e a disciplina já falhou duas vezes: a primeira foi o {AUD-43}, nos gatilhos, e este é o mesmo furo nas ações. Não há normalização no meio: o construtor grava o identificador da ação cru, direto da lista da tela.
- O que fazer: fazer as duas listas nascerem de uma fonte única, de modo que oferecer ação que o motor não executa deixe de ser possível, em vez de apenas deixar de acontecer, e acrescentar verificação que reprove na integração contínua quando as duas divergirem. Decidir no mesmo trabalho o destino de "mover etapa": ou passa a apontar para a rota que já funciona, ou sai da lista. Renomear o caso no motor faria o sintoma sumir e deixaria a raiz de pé, e o próximo par nasceria igual.
- Como verificar: comparar a lista de ações oferecida pela tela com o conjunto de ações que o motor executa e confirmar que são idênticas nos dois sentidos; configurar cada ação oferecida, rodar para um contato de teste e confirmar efeito real.
- Aceite (H1): Dado a lista de ações do editor de automações, Quando ela é comparada com as ações que o motor executa, Então as duas listas são idênticas, sem ação oferecida que o motor não execute nem ação no motor que a tela não ofereça, E a verificação que prova isso roda na integração contínua e reprova quando alguém acrescenta ação em um lado só, E nenhuma ação oferecida na tela termina uma execução como concluída sem ter efeito.
- Prioridade: alta. RFs: RF-AUTO-006 (Modelos de automação, emendado em 2026-07-16 por causa deste card), RF-AUTO-044. Descoberto em 2026-07-16, no planejamento do {AUD-68}.
- Este card era imortal até 2026-07-16, e a correção foi no documento, não nele: nenhum requisito reprovava o defeito que ele descreve. O RF-AUTO-006 exigia apenas que "uma automação editável é criada, E pode ser ajustada antes de ativar", e aplicar o modelo quebrado PASSA nesse aceite, porque a automação é criada e é editável. O RF-AUTO-044, por sua vez, ABENÇOA o estado atual, porque exige que configuração inválida vire falha nomeada, que é exatamente o que o {AUD-68} entregou. Requisito que não reprova nada não gateia nada, e por isso o RF-AUTO-006 foi emendado ANTES do código, do mesmo jeito que o {AUD-68} fez nascer o RF-AUTO-044. Quem alcança o requisito é o produto; o documento nunca baixa a promessa para caber no que existe.
- Sintoma: o modelo "Welcome + Tag" da biblioteca monta o passo de adicionar tag guardando o nome da tag (tag_name). O motor só age a partir do identificador da tag (tag_id). Todo usuário que aplicar esse modelo hoje recebe um passo que nunca vai funcionar.
- Correção de 2026-07-16, e ela é do tipo em que este roadmap já tropeçou antes: este card dizia que o passo "reporta sucesso para sempre". Isso é evidência ANTERIOR ao fix. O {AUD-68} entrou em produção em 2026-07-16 às 05:00, e as execuções concluídas daquele passo são de 2026-07-12. Hoje o passo falha alto, com o erro nomeado, e a automação para nele. O defeito que sobra é o certo, e é o único que este card entrega: o modelo continua montando um passo que não funciona, só que agora ele avisa. Comparar a data da evidência com a data do fix é obrigatório antes de repetir o sintoma de um card.
- Defeito PROVADO VIVO em 2026-07-16, com evidência POSTERIOR ao fix, que era exatamente o que faltava: às 15:39 daquele dia, em produção, o passo do modelo falhou com o motivo nomeado. A prova vale pelos dois lados e é por isso que ela importa: o modelo curado entrega mesmo uma automação que não funciona, E o {AUD-68} está funcionando, porque o registro ficou honesto em vez de mentir sucesso. Este card segue aberto de propósito: ele fecha quando o modelo parar de montar o passo quebrado, e não quando o registro passar a avisar que ele está quebrado.
- Onde o defeito não está, e isto importa: o painel de configuração está certo. Ele popula a lista a partir das tags da empresa e grava o identificador, e não conseguiria produzir o nome nem se quisesse. Quem gera o valor inútil é o modelo, e ele é código vivo, não dado velho de teste.
- Auditados os quatro modelos pelo mesmo critério, e não por amostra: só o "Welcome + Tag" tem o defeito. Os outros três (Follow-up automático, Notificação de negócio ganho, Tag-based follow-up) têm configuração coerente com o motor.
- Precedente idêntico: o {AUD-43} removeu um modelo que entregava automação quebrada em um clique, pela mesma razão.
- O que fazer: o modelo passa a montar o passo com o identificador da tag, e a tag que ele promete passa a existir de fato na empresa quando o modelo é aplicado (a empresa de teste tem uma tag, VIP, e não tem tag "novo": o nome do modelo não resolveria nem se o motor olhasse para ele). Verificar no mesmo trabalho que nenhum outro modelo grava configuração que o motor não honra.
- Como verificar: aplicar cada um dos quatro modelos numa empresa de teste, rodar para um contato e confirmar o efeito real de cada passo, e não apenas o passo concluído.
- Precisão do aceite (2026-07-16): o H1 anterior deste card exigia que "todo passo do modelo produz o efeito que promete". Ele colidia com a divergência deliberada do RF-AUTO-044 (empresa sem canal conectado gera passo ignorado, e não falha) e era impossível de passar na empresa de teste, que não tem canal conectado: os modelos que enviam mensagem cairiam em ignorado e reprovariam um aceite que não deveriam reprovar. O H1 abaixo reprova exatamente o defeito deste card, sem baixar a promessa e sem colidir com aquela divergência, e por isso ele testa a AUSÊNCIA de falha por configuração inválida, que é a marca do modelo quebrado, e não a presença de efeito, que depende do canal.
- Aceite (H1): Dado a biblioteca de modelos, Quando o administrador aplica qualquer um dos quatro modelos e roda a automação resultante para um contato de teste sem ter alterado nada nela, Então nenhum passo é registrado como falha por configuração inválida, E o passo de adicionar tag do modelo "Welcome + Tag" aplica a tag de fato no contato, verificável na ficha do contato e fora do próprio registro de execução, E a tag que o modelo promete existe na empresa depois que o modelo é aplicado, E passo registrado como ignorado por ausência de canal da empresa não reprova este aceite, porque é a divergência deliberada do RF-AUTO-044.
- Prioridade: alta. RFs: RF-AUTO-003 (Ações), RF-AUTO-044, e a família de Pagamentos. Descoberto em 2026-07-16, no planejamento do {AUD-68}.
- Sintoma: a ação "enviar fatura" (send_invoice) não emite fatura nenhuma. Ela insere uma atividade no histórico do contato com o título "Fatura enviada automaticamente pelo workflow". Mente duas vezes: no estado do passo, que fica concluído, e no registro, que afirma ao operador que uma fatura foi enviada.
- Por que o {AUD-68} não conserta isto: depois daquela fatia esta rota continua reportando concluído, porque ela faz com sucesso a coisa errada. O efeito que ela promete, a fatura, nunca chega a ser tentado, então não há erro nenhum a detectar. É o caso que mostra o limite exato do {AUD-68}.
- Agravante: aqui o registro falso é pior que o estado falso. O estado do passo hoje ninguém lê; a atividade no histórico do contato o operador lê, e ela afirma um envio que não houve.
- O que fazer: decidir entre emitir a fatura de verdade, e então a ação passa a fazer o que o nome diz, ou retirar a ação da lista enquanto ela não emitir, pela regra de honestidade da lista de ações do RF-AUTO-044. Enquanto a decisão não sai, a ação não pode continuar afirmando envio no histórico do contato.
- Como verificar: configurar a ação para um contato de teste, rodar, e confirmar que existe uma fatura de verdade, e não apenas uma atividade dizendo que existe.
- Aceite (H1): Dado uma automação com a ação de enviar fatura, Quando ela roda para um contato, Então existe uma fatura de verdade para aquele contato, E nenhum registro no histórico do contato afirma envio de fatura sem que a fatura exista; E, Dado que a decisão tenha sido retirar a ação, Então ela não é oferecida na lista de ações do editor.
- Prioridade: média. RFs: RF-AUTO-005 (Condições de saída), RF-AUTO-003 (Ações), RF-AUTO-044. Descoberto em 2026-07-16, no planejamento do {AUD-68}.
- Sintoma, primeira parte: a ação de condição (if_else) avalia a condição e não ramifica. Ela apenas registra o resultado e o fluxo segue em frente igual, tenha a condição dado verdadeiro ou falso. O próprio código admite por escrito que por ora só registra. É passo decorativo: o administrador monta uma bifurcação que não bifurca.
- Sintoma, segunda parte: a ação de criar tarefa está desativada de propósito, porque a tabela de tarefas não existe. Ela registra o erro no servidor e ainda assim reporta o passo como concluído. É o defeito do {AUD-68} admitido por escrito dentro do próprio código.
- Por que as duas estão no mesmo card: são a mesma classe (ação oferecida que não faz o que promete) e têm o mesmo desfecho depois do {AUD-68} (passam a falhar alto, que é o correto) e a mesma decisão de produto (implementar ou sair da lista). Separá-las daria dois cards com o mesmo veredito.
- O que fazer, criar tarefa: decidir entre mapear a tarefa para o histórico de atividades, que já existe, ou criar a tabela de tarefas. Enquanto não houver decisão, a ação sai da lista, pela regra de honestidade da lista de ações do RF-AUTO-044: ação desativada não pode ser oferecida.
- O que fazer, condição: implementar o desvio de verdade, ou retirar a ação da lista enquanto ela não desviar. O RF-AUTO-005 promete que o contato que atende à condição é retirado do fluxo e não recebe os passos seguintes, e hoje esse requisito está violado.
- Como verificar: montar uma automação com uma condição que dá falso e um passo distinto depois de cada ramo, rodar, e confirmar que o fluxo tomou o ramo certo; montar uma automação com a ação de criar tarefa e confirmar que a tarefa existe, ou que a ação não é oferecida.
- Aceite (H1): Dado uma automação com uma ação de condição e passos distintos em cada ramo, Quando ela roda para um contato, Então o fluxo segue exatamente o ramo correspondente ao resultado da condição, e não os dois nem sempre o mesmo, E, Dado a ação de criar tarefa, Quando ela roda, Então a tarefa existe de fato onde o produto a guarda, E, se qualquer uma das duas não estiver implementada, Então ela não é oferecida na lista de ações do editor.
- Prioridade: baixa, achado do qa do {AUD-68} (item 7, regressão real e correta). RFs: RF-AUTO-044, RF-AUTO-006. Descoberto em 2026-07-16, no qa do {AUD-68}.
- Sintoma: o workflow ativo "Welcome + Tag" (organização interna de dogfooding da própria Modulareasy) tem o passo de adicionar tag configurado com o nome da tag em vez do identificador, e esse nome nunca resolveu para uma tag existente na empresa. Antes do {AUD-68}, esse passo registrava concluído sem aplicar tag nenhuma, e o passo seguinte, enviar WhatsApp de boas-vindas, também era alcançado, embora também não enviasse nada, por falta de canal conectado. Depois do {AUD-68}, o mesmo passo é, corretamente, configuração inválida: fica em falha e a automação para. O WhatsApp de boas-vindas deixa de ser alcançado.
- Por que isto não é perda de efeito real: nenhum efeito real se perdeu. O passo de tag nunca aplicou tag, e o WhatsApp nunca enviou mensagem, nos dois lados da mudança, porque a empresa não tem canal de WhatsApp conectado. O que mudou foi a aparência do registro, de verde mentiroso sempre para vermelho verdadeiro quando a configuração é mesmo inválida. Registrado com honestidade porque, num workflow onde o passo seguinte funcionasse de verdade, ele deixaria de rodar a partir de agora, e é exatamente esse o comportamento que o RF-AUTO-044 exige.
- Alcance, auditado nas seis organizações do banco por critério e não por amostra: o padrão (adicionar tag pelo nome em vez do identificador) existe num único workflow, este. A Hiit, tenant piloto, tem zero workflows. Zero exposição a cliente pagante.
- Causa: o {AUD-75} (o modelo pronto que gera este mesmo defeito em um clique). Consertar o modelo não conserta os workflows que já nasceram dele antes do conserto; este card cobre o que já existe em produção, o {AUD-75} cobre a origem.
- O que fazer: apontar o passo de adicionar tag do workflow "Welcome + Tag" para uma tag real (criar a tag correspondente na organização, ou reaproveitar uma existente), ou reconfigurar a ação para algo que a organização realmente use.
- Como verificar: depois do ajuste, rodar o workflow para um contato novo e confirmar que o passo de tag aplica a tag de fato (linha real em contact_tags) e que o passo seguinte é alcançado.
- Aceite (H1): Dado o workflow "Welcome + Tag" corrigido, Quando ele roda para um contato novo, Então o passo de adicionar tag aplica uma tag real ao contato, E o passo seguinte de enviar WhatsApp é alcançado, seja concluído, seja ignorado por falta de canal, nunca interrompido por configuração inválida.
Achados do smoke visual real (2026-07-16)
O Wladimir abriu o Dashboard de Automações em produção (organização Modulareasy, sessão viva) depois de disparar um lead real, em modo claro e modo escuro, e confirmou visualmente o {AUD-68}: a execução do "Welcome + Tag" aparece Falhou, em vermelho, com o erro nomeado (Step add_tag failed: add_tag: configuracao invalida, tag_id ausente), e a Taxa de sucesso (30d) passou a mostrar 42,9% (6 de 14), um número honesto contra os 100% falsos de antes. O mesmo smoke revelou dois defeitos que nenhuma query tinha mostrado, abaixo.
- Prioridade: média, indicador de tela, não comportamento. Mesma família dos indicadores que contam errado ({AUD-33}). Descoberto em 2026-07-16, no smoke visual do {AUD-68}.
- Sintoma: o card "Workflows ativos" do painel de automações mostra 0, enquanto a lista de workflows ao lado, na mesma tela, mostra dois workflows marcados Ativo.
- Causa provável: em src/features/automation/overview-page.tsx, linha 122, o painel exibe metrics?.activeCount ?? 0; o valor vem de activeRes.count, em src/hooks/use-workflows.ts, linha 540, que conta errado o próprio objeto da tela. No banco, a contagem direta de workflows com status ativo e não excluídos, para a organização Hiit Fitwear, devolve 2.
- O que fazer: corrigir a contagem em use-workflows.ts para refletir o mesmo filtro que a lista usa (status ativo, não excluído), e confirmar que os dois números da mesma tela sempre concordam.
- Como verificar: com duas ou mais automações ativas, abrir o painel e confirmar que o indicador "Workflows ativos" mostra o mesmo número que a contagem visível na lista ao lado.
- Aceite (H1): Dado uma organização com N automações em status ativo, Quando o painel de automações é aberto, Então o indicador "Workflows ativos" mostra N, E esse número bate com a contagem de itens marcados Ativo na lista da mesma tela.
- Prioridade: alta, afeta 1503 dos 1528 contatos do tenant piloto real (98%, e não 100%: os 25 vindos de canal vivo estão corretos) e é pré-requisito do {AUD-61}. RFs: RF-AUTO-002 (Gatilhos), gestão de contato. Descoberto em 2026-07-16, no smoke visual do {AUD-68}; enunciado corrigido em 2026-07-16 pela medição por origem.
- Sintoma: o histórico de execuções de automação mostra um traço no lugar do nome do contato para os 1503 contatos da carga em lote, que são 98% da base do tenant piloto, e mostra o nome corretamente para os 25 que vieram de canal vivo.
- Correção de enunciado (2026-07-16): este card se chamava "o nome do contato está vazio em todos os registros" e afirmava que o produto "nunca preenche a coluna name". As duas coisas são falsas, e a medição por origem mostra por quê. Manual (a carga em lote de maio): 1503 contatos, 0 com name, 1492 com first_name. Livechat: 15, todos com name. Agendamento público: 4, todos com name. Formulário: 4, todos com name. Instagram e Messenger: 2, ambos com name. Ou seja, 25 dos 25 contatos vindos de canal vivo TÊM name preenchido. A divisão é limpa e cai exatamente em cima do caminho: a carga em lote preenche first_name; todo canal vivo preenche name. O produto preenche name, sim; o que é verdade é que a Hiit Fitwear tem 1503 contatos vindos todos do único caminho que preenche a outra coluna.
- Causa (o diagnóstico de fundo continua de pé, e é ele que sustenta o card): existem duas fontes para o mesmo fato, e cada caminho de escrita escolheu uma. A ficha do contato mostra o nome porque lê first_name; o histórico de execuções de automação lê name e por isso mostra o traço nos 1503 da Hiit. Duas fontes para o mesmo fato é a mesma doença que o {AUD-43} e o {AUD-74} já nomearam neste produto, e o H1 deste card ("existe exatamente uma fonte de nome") continua sendo o aceite correto.
- Precisão que vários cards deste roadmap erram e que muda a leitura do número: os 1503 são carga histórica em lote, e não tráfego de uso. Foram 1176 num único dia, 2026-05-11, mais 289 em 2026-05-12 e 35 em 2026-05-09. Tratar esse volume como se fosse fluxo do dia a dia superestima o alcance do defeito no uso corrente e subestima o risco da correção em massa, que é o assunto da linha seguinte.
- Por que isto amplia o {AUD-61}: o {AUD-61} responsabiliza o emissor por não carregar nome, telefone e e-mail no pacote do evento. Para os 1503 da carga em lote, mesmo que carregasse, a coluna que ele lê está vazia, então a variável de nome na mensagem continuaria vazia. São dois buracos em série para esse conjunto; consertar só o {AUD-61} não faz a variável funcionar para eles.
- Acoplamento com o {AUD-65}, declarado aqui e lá (o {AUD-65} carrega o espelho desta nota): o conserto deste card é uma atualização em massa nesses 1503 registros, e o gatilho de notificação de saída já dispara em atualização, não só em inserção. Se este card e o {AUD-65} se cruzarem na mesma janela sem lista de permissão por tipo de evento, este card vira o card que dispara automação para os 1438 contatos da Hiit que têm telefone. As duas fatias são incompatíveis na mesma janela; a ordem entre elas é decisão, não acaso.
- DECISÃO TOMADA (2026-07-16): first_name e last_name são a fonte única do nome do contato, e a coluna name é retirada. Este card deixa de ter decisão de produto pendente.
- Por que este lado é a fonte, e o argumento é de determinismo e não de preferência: o produto já promete o primeiro nome, porque uma variável de nome em mensagem ("Olá, {{contact.first_name}}") precisa saber onde o primeiro nome termina. A coluna name não sabe: derivar o primeiro nome dela é adivinhar pelo espaço, e adivinhar erra em nome composto e em sobrenome com preposição. O caminho inverso é determinístico e sem perda, porque montar o nome completo é juntar first_name com last_name. Quando um lado deriva do outro sem adivinhar e o inverso exige heurística, o lado sem heurística é a fonte.
- A migração é finita e conhecida, e por isso cabe numa fatia: os 1503 da carga em lote de maio já têm first_name (1492 preenchidos); os 25 de canal vivo têm só name e precisam ser convertidos. Ninguém tem os dois preenchidos, então não existe conflito a resolver caso a caso.
- O que esta decisão PERDE, declarado aqui porque perda que ninguém declara vira regressão: toda leitura de name passa a ler o par, e o histórico de execuções de automação é uma dessas leituras, justamente o sintoma que abriu este card. E qualquer consumidor externo que leia name pela interface de programação quebra. Esses consumidores precisam ser enumerados DENTRO da fatia, e não descobertos depois pelo cliente.
- Como enumerar os pontos de leitura, e isto é regra da fatia e não conselho: varrer pelos dois lados e por critério (backend, frontend, SQL e interface pública), nunca por busca do nome de um símbolo só. Buscar um símbolo só foi exatamente o que inflou o placar do {AUD-65} nesta mesma sessão, quando a varredura procurou o emissor do backend e não enxergou o do frontend.
- O que fazer: aplicar a decisão acima. Enumerar todos os pontos de leitura e escrita do nome, migrar os 25 contatos de canal vivo de name para first_name e last_name, passar toda leitura a ler o par, retirar a coluna name, e só então retomar o {AUD-61} sabendo que a origem tem dado. A lista de permissão por tipo de evento (fase F2 do {AUD-65}) entra ANTES desta fatia, pelo acoplamento declarado acima: sem ela, a atualização em massa dos 1503 vira o disparo de automação para os 1438 contatos reais da Hiit Fitwear.
- Como verificar: depois da decisão aplicada, conferir que 100% dos contatos, piloto e demais organizações, têm nome disponível pela fonte escolhida, e que o histórico de execuções de automação deixa de mostrar traço.
- Aceite (H1): Dado um contato criado por qualquer caminho do produto, Quando qualquer tela ou variável de mensagem lê o nome do contato, Então existe exatamente uma fonte de nome, E essa fonte está preenchida, E nenhuma tela mostra traço no lugar do nome.
- Prioridade: alta. RFs: RF-AUTO-002 (Gatilhos), RF-AUTO-044 (honestidade do que a tela oferece). Descoberto em 2026-07-16, na reconciliação dos cards do {AUD-65}.
- Sintoma: a função que decide se um evento casa com a configuração do gatilho (webhook-index.js, linhas 6606 a 6626) só tem ramo para dois gatilhos, contato respondeu e e-mail recebido. Todo o resto, inclusive contato criado, cai direto no retorno verdadeiro do fim da função. Na prática: a tela oferece o gatilho com configuração, o administrador preenche, salva, e o motor casa com tudo, ignorando o que ele preencheu.
- Por que não é o {AUD-74}, e isto foi conferido antes de abrir o card: o {AUD-74} trata da lista de AÇÕES da tela contra as rotas de ação do motor. Este trata da configuração dos GATILHOS. São superfícies diferentes e nenhum dos dois engole o outro. É a mesma família, e essa é a terceira ocorrência dela: o {AUD-43} achou o furo nos gatilhos oferecidos, o {AUD-74} achou nas ações, e este acha na configuração dos gatilhos. Afordância publicada sem motor atrás, de novo.
- Alcance a medir antes de corrigir: a ficha do Inventário de Artefatos descreve o gatilho de contato atualizado como disparando "só nos campos que o administrador marcar" ({AUD-53}). Essa promessa depende exatamente do filtro que esta função não tem. Enumerar, por critério e não por amostra, quais dos dezesseis gatilhos do RF-AUTO-002 oferecem configuração na tela e quais delas o motor honra.
- O que fazer: decidir por gatilho, e não no atacado. Gatilho cuja configuração a tela oferece e o motor não honra tem dois destinos honestos: o motor passa a honrar, ou a tela para de oferecer. Retorno verdadeiro por omissão é o desenho errado: o padrão seguro é recusar o que não se sabe casar, não aceitar. Não renomear e não remendar caso a caso, porque a raiz é que a função não tem uma fonte única dizendo quais gatilhos têm configuração e qual é.
- Como verificar: para cada gatilho que a tela oferece com configuração, montar uma automação com a configuração restritiva, disparar um evento que NÃO casa com ela e confirmar que a automação não executa; depois disparar um que casa e confirmar que executa.
- Aceite (H1): Dado uma automação com gatilho de contato criado e configuração restritiva preenchida na tela, Quando chega um evento de contato criado que não satisfaz essa configuração, Então a automação não executa, E nenhum gatilho oferecido com configuração na tela é casado pelo motor sem que a configuração seja avaliada, E gatilho cuja configuração o motor não sabe avaliar não é oferecido com configuração na tela.
- Prioridade: alta, e é pré-requisito de qualquer mudança de emissão. RF: RNF-003 (Confiabilidade da entrega assíncrona, "a idempotência evita efeito duplicado"). Descoberto em 2026-07-16, na reconciliação dos cards do {AUD-65}.
- Sintoma: a tabela de execuções de automação não tem restrição de unicidade nenhuma. Os índices existentes são a chave primária do identificador próprio e três índices de consulta, por automação, por empresa e por contato. Nenhum deles impede que o mesmo fato gere duas execuções.
- Por que isto é violação e não dívida: o RNF-003 é requisito publicado e diz, com todas as letras, que a idempotência evita efeito duplicado. Não há nada no banco que a garanta. Isto é verdade HOJE, independentemente de qualquer opção que o council do {AUD-65} escolha, e não é consequência dele: é um defeito vivo que ninguém sente só porque a maioria dos caminhos está muda. O dia em que os caminhos deixarem de ser mudos é o dia em que isto passa a doer.
- Por que é pré-requisito do {AUD-65}, e este é o ponto prático: com chave de idempotência, ligar um emissor novo convivendo com os emissores antigos é inofensivo, porque o segundo evento do mesmo fato não vira segunda execução. Sem ela, qualquer migração de emissão tem uma janela em que o contato real recebe a mensagem duas vezes. A ordem correta é esta antes daquela; inverter transforma uma decisão de arquitetura numa decisão sobre quanto duplicado é tolerado.
- O que fazer: definir a chave natural do fato (a combinação de automação, contato e evento de origem, com a identidade do evento vindo de quem o emite), aplicar a restrição no banco e não no código, e decidir o comportamento na colisão (ignorar em silêncio ou registrar a tentativa duplicada). A restrição vive no banco de propósito, pela mesma razão do {AUD-65}: no código ela é exaustiva por disciplina; no banco, por construção.
- ENTREGUE em 2026-07-16, e provado em produção: o mesmo fato disparado três vezes gera uma execução por automação, e não três; e depois de o serviço reiniciar, quatro automações distintas ficaram com exatamente uma execução cada. O RNF-003 sai de violado por construção e passa a cumprido.
- Limite honesto, e ele não pode sumir deste texto: a chave protege contra a mesma coisa acontecer duas vezes, e NÃO protege contra o aviso se perder no caminho. O salto do banco até o ouvinte continua sendo dispare e esqueça, exatamente como o {AUD-65} já registra sobre a fila. Idempotência e durabilidade são problemas diferentes, e só um deles foi resolvido aqui: ninguém pode vender a F3 do {AUD-65} como durabilidade resolvida por causa desta entrega. Quem ler "a idempotência resolveu a confiabilidade" sem esta ressalva vai medir errado o que foi entregue.
- Como verificar: emitir duas vezes o mesmo evento do mesmo fato para a mesma automação e o mesmo contato, e confirmar que existe exatamente uma execução registrada e que exatamente uma mensagem saiu.
- Aceite (H1): Dado uma automação ativa e um contato, Quando o mesmo evento do mesmo fato chega ao motor duas vezes, Então existe exatamente uma execução registrada, E exatamente um efeito aconteceu, E a garantia vem de restrição no banco, verificável na definição da tabela, e não de conferência no código.
- Prioridade: alta, e destrava envio real quando o {AUD-28} sair do parque. RFs: RF-AUTO-003 (Ações), RF-AUTO-044 (regra da empresa sem canal conectado), RF-CONV-054 (honestidade do envio). Descoberto em 2026-07-16, na reconciliação dos cards do {AUD-65}; reescrito no mesmo dia, quando o conjunto foi fechado pelos dois lados e o card deixou de ser sobre um emissor só.
- O card cresceu, e a correção é o começo dele: ele nasceu dizendo que "o envio de whatsapp da automação" não olha o canal, como se fosse um ponto. São QUATRO os pontos que despacham whatsapp, e nenhum decide pelo estado real do canal. Tratar um só era consertar um quarto do defeito e deixar a raiz viva, e a raiz é o que este card agora entrega.
- Contagem:
- Universo: 9. São os pontos do serviço que leem a configuração de canal de whatsapp da empresa, contados pela leitura dessa configuração, e NÃO pelo símbolo do envio, que é o erro que produziu o placar errado do {AUD-65}.
- Critério: comportamental. O ponto despacha uma mensagem de saída para o serviço externo do canal, ou apenas lê a configuração para outra finalidade.
- Placar: 4 despacham / 5 não despacham / 4 mais 5 é igual a 9. E dos 4 que despacham: 0 decidem pelo estado real do canal / 4 não decidem / 0 mais 4 é igual a 4.
- Lado negativo, lido por inteiro e não por amostra: dos 5 que não despacham, 4 são de ENTRADA (o webhook que recebe a mensagem do canal principal e autentica a instância pelo segredo; o roteamento que descobre a empresa pelo nome da instância na mensagem que chega; a verificação do webhook do canal alternativo; e o roteamento da mensagem que chega por ele) e 1 é de CONFIGURAÇÃO (grava o token de verificação quando o administrador liga a integração). Nenhum dos cinco manda mensagem para lugar nenhum.
- Controle positivo, e é ele que prova que o critério distingue de verdade: no mesmo serviço, o envio de SMS confere que o canal está conectado antes de despachar, em quatro lugares diferentes, um deles no mesmo trecho do robô de conversa, logo abaixo. O desenho certo já existe na casa e é ignorado justamente no whatsapp.
- Universo de dados é 1 tenant: SIM, e por isso este card NÃO diz "todas as empresas". Só uma empresa tem configuração de whatsapp gravada, a Hiit Fitwear. A afirmação sobre o CÓDIGO vale para qualquer empresa, porque é o código do produto; a afirmação sobre o ESTADO vale para a única que existe.
- Evidência de: 2026-07-16, no código em produção DEPOIS do {AUD-68} e do {AUD-82}, e não antes deles.
- Reprova por: RF-AUTO-044, no trecho literal do H1 "seja porque uma pré-condição legítima está ausente (o contato não tem telefone, a empresa não conectou o canal), Quando a automação roda para um contato, Então nenhum desses passos fica registrado como concluído, E o passo sem pré-condição fica registrado como ignorado, com o motivo nomeado". O ponto da automação chama o canal externo com o canal desconectado, e o desfecho não é ignorado com motivo nomeado: é imprevisível. E RF-CONV-054, que desde a emenda do {AUD-88}, entregue em 2026-07-16, alcança os quatro pontos e não mais só o do canal alternativo, no trecho literal do H1 "Quando qualquer ponto do produto que despacha mensagem de saída tenta enviar por aquele canal, independentemente de quem iniciou o despacho e de haver ou não pessoa diante da tela, Então o canal externo não é chamado", e ainda no trecho que fecha o placar por construção, "Então todo ponto desse conjunto confere que o canal está utilizável antes de despachar, E o placar fecha: os que conferem são o conjunto inteiro, e os que não conferem são nenhum". O ponto do robô de conversa era, até aquela emenda, o único que requisito nenhum reprovava, e é por isso que este card nasceu PAR com o {AUD-88}: sem ele, um quarto deste card seria imortal. Com o {AUD-88} fechado, o pré-requisito de documento deste card está cumprido, e nenhum dos quatro pontos passa no aceite pelo estado de hoje. Atenção ao desfecho, que o RF-CONV-054 emendado ramifica por iniciador em vez de uniformizar, e uniformizar aqui seria atropelar o RF-AUTO-044: no ponto do motor vale a Regra da empresa sem canal conectado, passo ignorado com o motivo nomeado e a automação segue, nunca falha; no ponto de quem despacha diante da tela, envio impedido ou marcado como falha, com aviso na hora. Único mesmo é o invariante: não chamar o canal não utilizável, e não afirmar envio que não houve.
- Os quatro pontos, nominalmente, e cada um erra à sua maneira: (1) o lembrete de agendamento pergunta por uma informação de estado que não existe na configuração, e por isso NUNCA envia, em silêncio: é o {AUD-84}, o mesmo defeito na direção oposta. (2) O robô de conversa lê só o nome da instância e responde ao contato: SEMPRE envia, e este ponto nunca foi listado em card nenhum até esta data. (3) A ação de automação lê só o nome da instância: SEMPRE envia, e ainda devolve a mensagem "empresa sem canal de whatsapp conectado" numa condição que nunca testou conexão nenhuma. (4) O envio pelo operador pelo canal alternativo confere se as credenciais existem, e não se o canal está utilizável: despacha do mesmo jeito. Este quarto é latente hoje, porque nenhuma empresa usa esse canal, e entra no card porque o lugar único precisa servi-lo também.
- Evidência medida, e ela é o pior caso possível: a Hiit Fitwear, tenant piloto real e única empresa com configuração de whatsapp gravada, tem nome de instância gravado e o canal marcado como não conectado. Ou seja, a única empresa com tráfego real do produto é exatamente a que passa pela condição e chega no canal externo com o canal desconectado.
- A raiz, e é ela que este card entrega: não existe um lugar único que responda "esta empresa tem whatsapp utilizável?". Cada ponto refaz a conferência à sua maneira, ou esquece dela, e é por isso que quatro pontos erraram de quatro jeitos diferentes. Consertar os quatro um a um é ser exaustivo por disciplina, e o quinto ponto que alguém escrever amanhã nasce errado de novo. É a mesma doença do {AUD-65}, e da mesma família do {AUD-68}: decidir pela PREMISSA (existe nome de instância, logo deve estar conectado) em vez de decidir pelo RESULTADO (está conectado).
- Por que a mensagem de retorno é o agravante: ela nomeia uma verificação que não existe, então quem lê o histórico acredita que a salvaguarda existe. A salvaguarda que todo mundo assume existir não existe, e alguém vai decidir em cima dela, inclusive a decisão do {AUD-65} sobre o gatilho.
- Risco hoje: contido apenas porque o {AUD-28} mantém o whatsapp estacionado. Vira defeito ativo no minuto em que o envio real for religado, e o efeito não é um erro visível: é o RF-AUTO-044 violado, porque a empresa sem canal conectado deveria gerar passo ignorado com motivo nomeado, e vai gerar chamada ao canal externo com desfecho imprevisível.
- O que fazer: criar o lugar único que responde se a empresa tem whatsapp utilizável, lendo o estado real do canal, e fazer os quatro pontos decidirem por ele em vez de cada um refazer a conferência. Empresa sem canal utilizável gera passo ignorado com o motivo nomeado, que é o que o RF-AUTO-044 exige, e a mensagem de retorno passa a dizer a verdade sobre o que foi verificado. Entra JUNTO com o {AUD-84}, e nunca antes dele: consertar o lembrete sozinho LIGA um canal que está morto desde sempre, e ligar um canal morto numa empresa com o canal desconectado é entregar exatamente o defeito que este card existe para matar.
- ENTREGUE em 2026-07-17, entrega única com o {AUD-84} e o {AUD-90} (merge aca9db6, gates de planejamento, revisão e qa verdes): nasceu o lugar único que responde se a empresa tem whatsapp utilizável, uma sonda ao vivo do estado real do canal, fail-closed em qualquer não-conclusão e sem cache, e os quatro pontos passaram a decidir por ele. Provado nas duas partes que o card exige: por construção, a sonda do canal aparece uma única vez no produto e mora dentro do lugar único, e nenhum dos quatro despachantes refaz a conferência; por mutação, trocado o corpo do lugar único por uma sentinela, os despachantes alcançáveis pararam juntos, cada um com a sentinela no registro próprio dele. O caminho infeliz foi exercitado ao vivo contra o serviço externo real para o lembrete e para o motor de automação (passo ignorado com o motivo nomeado, a automação segue, nunca falha); o robô de conversa e o operador do canal alternativo foram provados por leitura porque estão barrados fora deste escopo (a resposta automática de IA está desligada em produção por falta de chave, ver {AUD-97}; o envio pelo canal alternativo está estruturalmente morto, ver {AUD-96}). Corrigido também o defeito irmão do robô: ele só grava a mensagem como enviada depois do despacho aceito, nunca antes.
- Correções medidas a registrar (o card exagerava, e a reconciliação registra o que se mediu): (1) o pior caso descrito acima não estava vivo. Nenhum dos quatro pontos alcançava o serviço externo para o tenant piloto, cada um barrado por um acidente diferente: a rotina de lembrete morria na coluna inexistente, o robô nunca dispara sem mensagem de entrada e não há instância que a entregue, o motor não tem automação de whatsapp na empresa real, e o canal alternativo ninguém usa. O defeito de código era real e vale para qualquer empresa; o estado descrito como vivo não estava. (2) O controle positivo do envio de SMS prova a forma, não a substância: o estado conectado do SMS é gravado como verdadeiro fixo ao salvar as credenciais, sem nunca conferir nada com o serviço externo, e nada o reverte. Ele prova que existe um portão, não que o portão é honesto, e por isso o desenho sonda ao vivo em vez de espelhar o SMS. (3) A instância gravada no banco não existe no serviço externo (a consulta de instâncias responde vazio), o que torna o caminho feliz não exercitável sem uma fixture do mundo externo, e foi assim que o {AUD-84} o provou.
- Como verificar: numa empresa com nome de instância gravado e canal desconectado, exercitar os quatro pontos e confirmar que nenhum chama o canal externo; e conferir que a decisão vem de um lugar só, apagando esse lugar e vendo os quatro pararem juntos, em vez de quatro conferências independentes continuarem de pé.
- Aceite (H1): Dado uma empresa com nome de instância gravado e o canal marcado como não conectado, Quando qualquer um dos quatro pontos que despacham whatsapp tenta enviar para um contato com telefone, Então nenhuma chamada é feita ao serviço externo do canal, E o passo de automação fica registrado como ignorado com o motivo nomeado, E nenhuma mensagem de retorno do produto afirma uma verificação que o código não faz, E a decisão de "o canal está utilizável" é lida de um único lugar do produto, verificável porque nenhum dos quatro pontos refaz a conferência por conta própria.
- Prioridade: alta. RFs: RF-CAL (lembretes de agendamento), RNF-006 (Observabilidade). Descoberto em 2026-07-16, na reconciliação dos cards do {AUD-65}. Irmão direto do {AUD-52}.
- Irmanado ao {AUD-83}, e a ordem NÃO é sugestão (registrado em 2026-07-16): este card é o MESMO defeito na direção oposta. Lá, três pontos despacham sem olhar o estado do canal e SEMPRE enviam; aqui, o ponto pergunta por uma informação de estado que não existe e NUNCA envia. A raiz é uma só, e é a ausência de um lugar único que responda se a empresa tem whatsapp utilizável. A consequência é prática e cara: consertar este card sozinho LIGA um canal que está morto desde sempre, e ligá-lo numa empresa com o canal desconectado, que é o estado do único tenant real, é entregar exatamente o defeito do {AUD-83}. Este card entra JUNTO com o {AUD-83}, nunca antes.
- Sintoma: a rotina de lembretes (webhook-index.js, linha 2049) lê a configuração de whatsapp da empresa pedindo o nome da instância e uma coluna chamada status. Essa coluna NÃO existe na tabela: as colunas de estado que existem são conectado e situação da instância. A consulta erra, a variável fica nula, a condição que exige nome de instância e situação aberta é falsa, e o lembrete morre ali. Sem exceção, sem registro, sem nada.
- Por que passou despercebido: o retorno de erro da consulta é descartado (só o dado é lido), então o erro nunca vira exceção e o bloco de captura ao redor nem chega a registrar aviso. Rota que morre em silêncio não aparece em lugar nenhum, que é exatamente o que o {AUD-50} já tinha dito com outras palavras sobre a coleta de e-mail.
- Consequência que muda a leitura do {AUD-52}: o {AUD-52} parte da premissa de que "o lembrete já é enviado hoje, sozinho, pelo agendador", e por isso desenha toda a virada em torno do risco de lembrete DUPLICADO, com a exigência de desligar o agendador na mesma entrega. Se o caminho de whatsapp do agendador nunca disparou, esse risco não existe para esse canal, e a virada do {AUD-52} é mais simples do que ele supõe. O {AUD-52} não deve ser executado sem antes medir, canal por canal, o que o agendador de fato manda hoje: a premissa dele está em dúvida.
- O que fazer: decidir com o {AUD-52} junto, porque os dois mexem no mesmo lembrete. Se o {AUD-52} for adiante, este caminho morre de qualquer jeito e o conserto é só parar de mentir enquanto ele vive. Se o {AUD-52} demorar, a consulta passa a ler as colunas que existem e a decidir por elas, e o erro da consulta passa a ser registrado em vez de descartado. Nos dois casos, o erro descartado é o defeito de raiz, e ele não é desta rota só.
- ENTREGUE em 2026-07-17, entrega única com o {AUD-83} e o {AUD-90} (merge aca9db6, gates verdes): a rotina de lembrete parou de pedir a coluna que não existe e passou a decidir pelo lugar único do {AUD-83}, e o erro da consulta passou a ser registrado em vez de descartado. O caminho feliz foi provado ao vivo, mas contra uma fixture do mundo externo (um serviço substituto que responde canal aberto), nunca contra o serviço real nem com telefone real, porque a instância do tenant piloto não existe no serviço externo e parear uma exige um telefone humano: com a fixture, a rotina rodou, a mensagem saiu e o agendamento foi marcado como lembrado. O caminho infeliz foi provado contra o serviço externo real: sem instância, a rotina não despacha, registra o motivo nomeado e não marca o agendamento como quebrado. Já há registro de produção do portão vivo, com o motivo nomeado no log próprio da rotina.
- Como verificar: com um agendamento de teste com lembrete configurado por whatsapp numa empresa com canal conectado, a rotina roda e a mensagem chega; com a consulta errando, o registro do serviço mostra o erro em vez de silêncio.
- Aceite (H1): Dado um agendamento com lembrete por whatsapp configurado numa empresa com canal conectado, Quando a rotina de lembretes roda, Então o lembrete é enviado, E, Dado que a leitura da configuração falhe por qualquer motivo, Quando a rotina roda, Então a falha fica registrada com o erro nomeado, E nenhuma falha de leitura faz o lembrete sumir sem deixar rastro.
- Prioridade: média (rebaixada em 2026-07-16, e a medição é o motivo, não o cansaço). RFs: RF-AUTO-002 (Gatilhos), RF-CONV-054 (não afirmar sucesso sem efeito), RNF-006 (Observabilidade). Descoberto em 2026-07-16, na reconciliação dos cards do {AUD-65}.
- Sintoma: a função que emite eventos a partir da tela (src/lib/fire-event.ts) aguarda a chamada da rota de eventos e nunca confere o código de retorno da resposta. Aguardar uma chamada não levanta erro quando a resposta é 401, 403, 404 ou 500: o erro só aparece em falha de rede. Existe um aviso no registro do navegador, e ele é enganoso, porque só dispara no caso que quase nunca acontece e nunca no caso que interessa.
- Alcance, nominal: todo evento emitido pela tela passa por aqui. Contato criado (a criação rápida e a criação pela tela), tag adicionada, tag removida, agendamento marcado, etapa alterada, oportunidade ganha e oportunidade perdida. Sete fatos, um único ponto de silêncio.
- Por que isto é agudo hoje: a rota de eventos passou a exigir sessão válida e vínculo com a empresa quando o {AUD-47} fechou o barramento sem autenticação. A partir dali, uma sessão expirada ou um vínculo ausente devolve 401 ou 403, e esta função trata os dois como sucesso. É o mesmo sucesso fingido que o RF-CONV-054 condena e que o {AUD-68} acabou de matar no motor: aqui ele está vivo, do lado da tela.
- A dúvida "será que emite?" está RESPONDIDA, e é por isso que este card mudou de tom (medido em produção em 2026-07-16): o cadastro rápido foi exercitado, a rota respondeu com sucesso e o servidor registrou o evento. Emite. O que este card entrega deixa de ser a descoberta de um emissor duvidoso e passa a ser só a cegueira: a emissão acontece hoje, e no dia em que ela for recusada ninguém ficará sabendo. Isso é risco latente e não falha viva, e a prioridade caiu para média por causa dessa distinção, e não porque o defeito tenha sumido. O histórico do registro continua sem coincidência entre emissão e contato nascido, e isso nunca foi sintoma de quebra: era ausência de tráfego, e a medição direta desempatou o que trinta dias de registro não desempataram. Este card conserta a cegueira, e não um sintoma medido: o sintoma é justamente que não há sintoma.
- O que fazer: a função passa a conferir o código de retorno e a tratar recusa como falha, com o erro nomeado no registro. Decidir, no mesmo trabalho, o que a tela faz quando a emissão falha: o desenho de dispare e esqueça é legítimo para não travar a interface, mas dispare, esqueça e minta não é. O mínimo honesto é o registro; se a emissão for parte do que o usuário acredita ter feito, ela precisa de tratamento visível.
- Como verificar: forçar a rota de eventos a recusar (sessão sem vínculo com a empresa) e confirmar que a falha aparece nomeada no registro do navegador em vez de passar como sucesso silencioso.
- Aceite (H1): Dado a tela emitindo qualquer um dos sete eventos, Quando a rota de eventos responde com recusa ou erro, Então a falha é detectada e fica registrada com o código e o evento nomeados, E nenhuma resposta de erro é tratada como sucesso, E nenhum caminho da tela afirma ao usuário que fez o que não fez.
- Prioridade: média hoje (latente, e a linha de risco explica), alta no dia em que o recurso for usado. RFs: RF-AUTO-006 (Modelos de automação), RNF-001 (isolamento entre empresas), RNF-010 (Perímetro autenticado). Descoberto em 2026-07-16, na reconciliação dos cards do {AUD-65}.
- O defeito não é o que se supôs, e a correção do diagnóstico é o começo do card: a suspeita apontava a função de banco que aplica snapshot. Ela é código morto, provado: referencia duas colunas que não existem na tabela de automações (uma de passos e uma de ativo, e a tabela tem status, não ativo), então ela erraria se fosse chamada, e a tabela de aplicações de snapshot tem zero linhas. O caminho vivo é outro, a rota de aplicar snapshot (webhook-index.js, linha 5050), e é nela que estão os dois defeitos.
- Defeito 1, a tag que atravessa a parede: a rota recria as tags no destino, e elas nascem com identificadores novos, como tem que ser. Mas ela insere os passos das automações copiando a configuração literalmente, do jeito que estava na origem. A configuração do passo de tag carrega o identificador da tag DA EMPRESA DE ORIGEM. Como a rota escreve com a chave de serviço, a regra de isolamento por linha não barra. Resultado: um contato da empresa de destino recebe uma tag da empresa de origem. É vazamento entre empresas por dado, e o RNF-001 não admite.
- Defeito 2, o oposto do que o próprio produto mandou por escrito: a rota grava as automações com status ativo. A função de banco morta, na mesma casa, documenta a intenção em comentário: insere inativo por segurança, e o super administrador habilita à mão após revisão. A intenção de segurança existe escrita, e o código vivo faz exatamente o contrário. Automação copiada de outra empresa nasce ligada, disparando, sem ninguém ter revisado.
- Risco hoje, sem maquiagem: latente. O único snapshot existente tem automações sem passos, e há zero aplicações registradas. Nada aconteceu ainda. Vira dano no primeiro uso real do recurso, e o dano tem as duas metades juntas: automação ligada sozinha aplicando tag de outra empresa em contato alheio.
- Por que os dois defeitos vão no mesmo card: são a mesma rota e a mesma entrega. Consertar o status e deixar a tag atravessando entrega uma automação inofensiva que vira nociva quando alguém a liga; consertar a tag e deixar o status ligado entrega automação correta disparando sem revisão. Separar cria a janela.
- O que fazer: a rota passa a remapear, na cópia dos passos, toda referência a identificador da origem para o identificador correspondente no destino (tag e funil, no mínimo; enumerar por critério e não por amostra quais tipos de passo carregam referência). Referência sem correspondente no destino não vira passo silenciosamente quebrado: é erro nomeado na aplicação do snapshot. E a automação copiada nasce inativa, honrando a intenção já escrita. Decidir no mesmo trabalho o destino da função de banco morta: ou volta a ser o caminho vivo e correto, ou sai, porque código morto que documenta a intenção certa enquanto o código vivo faz o oposto é a pior das duas fontes de verdade.
- Como verificar: aplicar um snapshot com automação que tenha passo de tag numa empresa de destino diferente da origem, e conferir que a tag do passo aponta para a tag da empresa de destino, que nenhuma tag da origem alcança contato do destino, e que a automação aparece inativa na lista aguardando revisão.
- Aceite (H1): Dado um snapshot de uma empresa com automação que aplica tag, Quando o super administrador o aplica em outra empresa, Então todo passo copiado aponta para referências da empresa de destino, E nenhum identificador da empresa de origem sobrevive na configuração dos passos do destino, E toda automação copiada nasce inativa, E referência sem correspondente no destino produz erro nomeado em vez de passo silenciosamente quebrado.
- Prioridade: média. RF: RF-AUTO-006 (Modelos de automação, na emenda de 2026-07-16). Descoberto em 2026-07-16, no review do {AUD-75}.
- Sintoma: ao aplicar um modelo de automação, o produto cria a automação e depois cria a tag que o modelo promete. Se a criação da tag falhar por rede, o trecho que deveria tratar o erro não o trata: ele apenas encerra a etapa e segue. A automação fica criada e VAZIA, e o usuário não recebe aviso nenhum. Ele vê o modelo aplicado, abre a automação e não há passo nenhum lá dentro.
- Lacuna pré-existente que o {AUD-75} agora encosta, e é por isso que este card nasce agora: o defeito não nasceu com o {AUD-75}, já estava lá. O {AUD-75} o encosta porque passa a criar a tag no ato de aplicar o modelo, que é justamente o passo que pode falhar. Consertar o {AUD-75} sem este card troca um defeito conhecido (o modelo entrega passo quebrado, e avisa) por um defeito silencioso (o modelo entrega automação vazia, e não avisa), e silencioso é pior. Os dois andam juntos.
- Reprova por: RF-AUTO-006, no trecho literal do H1 "Quando o administrador aplica um modelo, Então uma automação editável é criada a partir dele, E pode ser ajustada antes de ativar, E todo passo dela aponta para referências que existem na empresa e que o motor resolve (a tag pelo identificador dela, o funil pelo identificador dele)". Automação sem passo nenhum não tem passo que aponte para referência que existe. A regra do modelo aplicável, emendada no mesmo dia, é ainda mais direta: "um modelo que só funciona após edição manual não é modelo, é um rascunho quebrado". Automação vazia não funciona nem após edição manual, porque não há o que editar.
- O que fazer: a aplicação do modelo passa a tratar a falha da criação da tag em vez de segui-la em frente. Decidir no mesmo trabalho entre desfazer a automação criada (aplicar tudo ou nada) e mantê-la avisando o que faltou; a recomendação é tudo ou nada, porque automação vazia e silenciosa é o pior desfecho possível deste requisito, pela mesma razão que o RF-AUTO-044 dá para o passo que afirma sucesso sem efeito. Em qualquer das duas escolhas, o usuário fica sabendo.
- Como verificar: aplicar um modelo forçando a falha da criação da tag, e confirmar que o administrador recebe o erro nomeado na tela e que não sobra automação vazia e silenciosa na lista.
- Aceite (H1): Dado a biblioteca de modelos, Quando o administrador aplica um modelo e a criação da tag que o modelo promete falha, Então o administrador recebe o erro nomeado na tela, E não sobra automação criada sem passo nenhum, E nenhum caminho da aplicação do modelo termina em sucesso aparente com a automação vazia.
- Prioridade: alta. RF: RNF-009 (Operação e implantação). Descoberto em 2026-07-16, durante o teste do {AUD-75}.
- Sintoma: o arquivo de entrada do sistema é servido sem nenhuma instrução de validade. Sem essa instrução, o navegador decide sozinho por quanto tempo guarda a página, e enquanto durar esse prazo ele continua carregando a versão antiga do sistema, mesmo depois de uma publicação nova. O usuário não vê a correção que já está no ar, e não tem como saber disso: para ele o sistema simplesmente continua com o defeito.
- Por que isto é grave além do incômodo: durante o teste do {AUD-75} o defeito corrigido reapareceu duas vezes como se estivesse vivo, porque o navegador estava servindo a versão anterior guardada. Quem testou quase registrou como reprovado um conserto que estava correto. Ou seja, isto não atrasa só o usuário: ele contamina a própria verificação do produto, e pode fazer a casa consertar duas vezes o que já estava consertado, ou declarar quebrado o que já funciona.
- Escopo: a instrução de validade vale para o arquivo de entrada, que é o que aponta para todo o resto. Os demais arquivos publicados já carregam identificação própria de versão no nome e podem continuar sendo guardados por muito tempo, que é o desejado.
- H1: Dado que uma versão nova do sistema foi publicada, Quando o usuário abre ou recarrega o sistema no navegador que já o havia aberto antes, Então ele recebe a versão nova, sem precisar limpar o histórico do navegador nem forçar recarregamento, E o navegador confere com o servidor se há versão nova a cada abertura, em vez de decidir sozinho por um prazo próprio.
- Como verificar: publicar uma versão nova e abrir o sistema num navegador que já tinha a versão anterior guardada, sem limpar nada. A versão nova aparece. Conferir também que a resposta do arquivo de entrada traz a instrução de validade, e que os demais arquivos continuam guardados por muito tempo.
- Entregue em 2026-07-16, e o H1 está fechado pelos dois lados, por execução e não por dedução. A página de entrada passou a ser conferida com o servidor a cada abertura, e os demais arquivos, que já carregam identificação de versão no próprio nome, seguem guardados por muito tempo, que é o desejado. As duas metades do aceite foram medidas em separado. A primeira, que o navegador confere a cada abertura: em navegador real com perfil que persiste, em três aberturas seguidas e sem limpar nada, a página de entrada foi conferida com o servidor todas as três vezes, enquanto os 34 pedidos dos demais arquivos vieram do arquivo local do navegador sem ida ao servidor: o conserto é seletivo, e foi provado seletivo. A segunda, que quem tem versão antiga recebe a nova: um navegador que guardava a versão atual recebeu a resposta curta de zero byte, e um navegador que guardava versão obsoleta recebeu a versão nova inteira, sem limpar nada e sem forçar recarregamento. Como a página de entrada é a que nomeia todos os demais arquivos pela versão deles, recebê-la nova é receber o sistema novo, e não existe no produto nenhuma outra camada de guarda que possa contornar isso. O que NÃO foi exercitado, e fica registrado: a cerimônia completa de publicar uma versão nova e vê-la aparecer, porque não houve publicação nova durante o teste. O que se fez foi medir cada elo da corrente em separado, inclusive o elo decisivo, que é o navegador com versão antiga pedindo e recebendo a nova. Resta um efeito de transição, honesto e que se resolve sozinho: o navegador que guardou a página de entrada ANTES desta entrega a guardou sem instrução de validade nenhuma, e pode levar a própria janela curta dele para voltar a perguntar, uma única vez. Nenhum conserto desta natureza alcança o que já foi entregue antes dele, e o aceite não pode exigir isso. Fica registrada também uma imprecição deste próprio card, que a entrega revelou e que marcar o card não conserta: ele cita como requisito o RNF-009, que trata de isolamento de infraestrutura entre produtos e não alcança nada do que este card trata. Nenhum requisito publicado reprova o defeito que este card corrigiu, o que o tornaria imortal se ele não tivesse sido feito. É a mesma lacuna do {AUD-92}, na família de operação e implantação em vez da de credenciais, e ela segue aberta.
- Prioridade: alta, e é PAR do {AUD-83}: sem este card, um quarto daquele é imortal. RF: RF-CONV-054 (Honestidade do envio), que este card emenda. Descoberto em 2026-07-16, na reescrita do {AUD-83}.
- O defeito é do documento e não do produto, e por isso este card vem ANTES do código: dos quatro pontos que despacham whatsapp, três são reprovados por requisito publicado e um não é reprovado por nenhum. O RF-CONV-054 só dispara "Quando o operador tenta enviar uma mensagem", e o robô não é o operador. O RF-AUTO-044 só dispara "Quando a automação roda para um contato", e o robô respondendo uma conversa não é uma automação. E o RF-CONV-025 é pior que omisso, ele ABENÇOA o estado: diz que em Piloto Automático "o bot passa a responder automaticamente sem revisão", e não diz uma palavra sobre conferir o canal. O robô pode despachar com o canal desconectado para sempre sem violar linha nenhuma do documento.
- Por que isto é a mesma doença do {AUD-75}, e a casa acabou de aprender: requisito que não reprova nada não gateia nada. O {AUD-75} foi card imortal até o RF-AUTO-006 ser emendado em 2026-07-16, e a correção foi no documento, não no card. Aqui é idêntico: enquanto o requisito não reprovar, consertar o robô é opcional, e um dia alguém fecha o {AUD-83} deixando o robô de fora e nada acusa.
- O verbo delimita, e essa é a lacuna exata: "o operador tenta enviar" não alcança "o robô responde". Quem despacha mensagem para o contato hoje é o operador pela tela, o motor de automação, a rotina de lembretes e o robô de conversa. O requisito de honestidade do envio precisa nomear o conjunto, e não um dos quatro. Enumeração ilustrativa não serve, pelo mesmo motivo que derrubou o RF-AUTO-002 no {AUD-43}: nomear o conjunto exato, ou dar a regra que o gera.
- O que fazer: emendar o RF-CONV-054 ANTES do código do {AUD-83}, trocando o gatilho do H1 de "o operador" para qualquer despachante do produto (o operador pela tela, o motor de automação, a rotina de lembretes e o robô de conversa), de modo que o requisito reprove o despacho com canal não utilizável venha ele de quem vier. A divergência deliberada do RF-AUTO-044 continua valendo onde ela vale: no motor, empresa sem canal conectado gera passo ignorado e não falha, e esta emenda não pode atropelar isso.
- Como verificar: com o requisito emendado, conferir que cada um dos quatro despachantes do {AUD-83} tem no H1 um fato que o reprova quando despacha com o canal não utilizável, e que nenhum deles passa no aceite pelo estado de hoje.
- Aceite (H1): Dado o RF-CONV-054 emendado, Quando qualquer despachante do produto (o operador pela tela, o motor de automação, a rotina de lembretes ou o robô de conversa) tenta enviar mensagem numa empresa cujo canal não está utilizável, Então o requisito reprova o envio, E nenhum dos quatro despachantes fica fora do alcance do H1, E o {AUD-83} passa a ter requisito que o reprove nos quatro pontos.
- Entregue em 2026-07-16: o RF-CONV-054 foi emendado e publicado. O conjunto passou a ser dado por PROPRIEDADE, e não por lista: a Regra do alcance diz "todo ponto do produto que despacha mensagem de saída para um canal externo, seja qual for o iniciador", e o card autorizava as duas saídas (nomear o conjunto exato ou dar a regra que o gera), das quais esta é a superior, porque enumerar os quatro deixaria o quinto despachante de fora no dia em que ele nascesse, que é ser exaustivo por disciplina, o vício que o {AUD-65} existe para matar. O H1 passou a exigir o invariante único (não chamar o canal não utilizável, não afirmar envio que não houve) com o desfecho ramificado por iniciador, e a fechar placar por construção, de modo que a divergência deliberada do RF-AUTO-044 não foi atropelada: ela deixou de ser divergência e virou a instância da regra no motor, com o passo ignorado intacto. O RF-CONV-025 ganhou ressalva remissiva ao RF-CONV-054, porque abençoar o estado é pior que ser omisso. Duas frases do RF-AUTO-044 foram reconciliadas, que a emenda tornou falsas sem tocar na decisão que elas carregam. E o {A-069} do Plano de Testes voltou a aberto: estava validado desde 2026-07-11 exercitando só o operador, e com o requisito endurecido o aceite deixou de estar coberto. O {AUD-83} agora tem requisito que o reprove nos quatro pontos, e nenhum despachante futuro nasce fora do alcance.
- Prioridade: alta, e entra JUNTO com o {AUD-83}, nunca depois: é o mesmo ponto do produto e a mesma entrega. RFs: RNF-002 (Segurança de credenciais), que hoje NÃO alcança este defeito, e é por isso que este card nasce PAR com o {AUD-92}. Relacionado com o {AUD-83}, o {AUD-84} e o {AUD-28}. Descoberto em 2026-07-16, por execução real, durante a verificação do {AUD-89}.
- O defeito, e ele é de duas naturezas ao mesmo tempo: dos três pontos do produto que chamam o serviço externo do canal principal para entregar uma mensagem, dois se identificam com a credencial que vem da configuração do ambiente, e um se identifica com uma credencial escrita por extenso, letra a letra, dentro do próprio código. As duas são diferentes entre si, e a que está escrita no código não é a que o serviço do canal reconhece como sua. Credencial escrita no código já é defeito por si só, mesmo que funcionasse: ela não pode ser trocada sem republicar o sistema, ela viaja para todo lugar em que o código viaja, e ela não é a que a operação configurou.
- Contagem:
- Universo: 3. São os pontos do serviço que chamam o serviço externo do canal principal de whatsapp para entregar uma mensagem, contados pela chamada de entrega ao serviço externo, e NÃO pelo símbolo da credencial, que é justamente o erro que produziu o placar errado do {AUD-65}. Os quatro pontos do {AUD-83} não são este universo: um daqueles despacha pelo canal alternativo, que tem credencial própria, de outra natureza, alheia a esta, e por isso ele fica de fora deste card sem ficar de fora daquele.
- Critério: comportamental. O ponto chama o serviço externo do canal principal para entregar mensagem a um contato, e a pergunta é com qual credencial ele se identifica: a que vem da configuração do ambiente, ou uma escrita no código.
- Placar: 1 se identifica com credencial escrita no código / 2 se identificam com a credencial da configuração / 1 mais 2 é igual a 3.
- Lado negativo, lido por inteiro e não por amostra: os 2 que usam a credencial da configuração são a rotina de lembretes de agendamento e o robô de conversa, ambos lidos por inteiro no código que está publicado, e ambos se identificando com o valor que vem da configuração, sem nenhum literal.
- Controle positivo, e é ele que prova que o critério distingue de verdade: chamando o serviço do canal com cada uma das duas credenciais, elas se comportam de modo diferente, a da configuração é aceita e a do código é recusada. Não é leitura, é execução: as duas foram enviadas ao serviço e ele respondeu diferente para cada uma.
- Universo de dados é 1 tenant: SIM, e por isso este card NÃO diz "todas as empresas". Só uma empresa tem configuração de whatsapp gravada. A afirmação sobre o CÓDIGO vale para qualquer empresa, porque é o código do produto.
- Evidência de: 2026-07-16, no código em produção DEPOIS do {AUD-68} e do {AUD-89}, e não antes deles.
- Reprova por: NENHUM requisito publicado, e é este o motivo de o card nascer PAR. O RNF-002 governa credencial guardada e credencial exibida, e o verbo delimita: "segredos não aparecem em tela nem em log" não alcança segredo escrito no código, que não é tela nem log, e a decisão de arquitetura que sustenta o RNF-002 é explícita em mirar o vazamento da base de dados. É a mesma doença do {AUD-88} e do {AUD-43}: enquanto o requisito não reprovar, consertar isto é opcional, e um dia alguém fecha o {AUD-83} deixando este ponto como está e nada acusa. O {AUD-92} endurece o requisito, e vem ANTES deste card.
- O que este card NÃO afirma, e esta é a parte mais importante dele: ele NÃO afirma que a entrega da automação seria recusada, e NÃO afirma que este ponto nunca entregaria mensagem nenhuma. A recusa da credencial do código foi medida numa chamada de consulta geral ao serviço do canal, que não é a chamada de entrega. A chamada de entrega não pôde ser exercitada, porque hoje não existe nenhuma linha ativa no serviço do canal: a única empresa com configuração gravada aponta para uma linha que o serviço não tem, e por isso toda entrega hoje falha por ausência de linha, com qualquer credencial, antes mesmo de a credencial ser conferida. Enquanto o {AUD-28} mantiver o canal estacionado, o efeito desta credencial na entrega é inobservável. O que está provado é a divergência, e ela basta: o produto se identifica de dois jeitos diferentes para o mesmo serviço, e um deles não é o que a operação configurou.
- A tentação que este card existe para matar, e ela quase pegou quem o escreveu: existem no sistema seis registros de passo de automação de envio de whatsapp marcados como concluídos, em 2026-07-11 e 2026-07-12, com a credencial do código já no lugar desde 2026-04-17. Lidos de fora, eles pareceriam prova de que a credencial do código funciona. Não são: até 2026-07-16, quando o {AUD-68} foi entregue, aquele ponto não olhava a resposta do serviço e dava o passo por concluído sem conferir nada. Os seis concluídos são o registro histórico do defeito do {AUD-68}, e não prova de entrega. Nenhuma mensagem de saída de whatsapp originada de automação existe no histórico do produto, em nenhuma data.
- Agravante do mesmo defeito de raiz: a mesma credencial escrita no código é usada como valor de reserva da configuração, para o caso de a configuração do ambiente estar ausente. Ou seja, se um dia a configuração sumir, os três pontos, e não só um, passam a se identificar em silêncio com a credencial que o serviço do canal recusa, sem nenhum aviso de que isso aconteceu. Um valor de reserva escrito no código transforma configuração ausente, que deveria ser um erro alto e imediato, em degradação silenciosa.
- Por que este card muda o {AUD-83}, e é este o efeito prático dele: o {AUD-83} descreve este ponto como "SEMPRE envia". Isso é o que o código PRETENDE, e não o que ele consegue. O ponto sempre CHAMA, e o que acontece depois não é uma entrega garantida: ele se identifica com uma credencial que o serviço do canal não reconhece como sua. Quem fechar o {AUD-83} e o {AUD-84} e religar o canal vai declarar o envio da automação entregue, e ele pode continuar mudo, pelo motivo que este card nomeia e que aquele card não vê. É a mesma família do {AUD-84}, caminho que nunca funcionou em silêncio, e do "nunca falhou é indistinguível de nunca rodou".
- O que fazer: o ponto que se identifica com a credencial escrita no código passa a se identificar com a mesma credencial que os outros dois, lida da configuração, e o valor de reserva escrito no código deixa de existir: configuração de credencial ausente vira falha nomeada na subida do serviço, e não uma reserva silenciosa. Nenhuma credencial do produto fica escrita no código. Feito isso, os três pontos se identificam pelo mesmo lugar, e a operação consegue trocar a credencial sem republicar o sistema.
- ENTREGUE em 2026-07-17, entrega única com o {AUD-83} e o {AUD-84} (merge aca9db6, gates verdes): a credencial escrita por extenso no código deixou de existir (zero ocorrências), o ponto que a usava passou a se identificar com a credencial da configuração, e o valor de reserva escrito no código foi removido, de modo que configuração de credencial ausente agora derruba o serviço na subida com erro nomeado em vez de degradar em silêncio. A primeira metade do aceite está provada: apagando a configuração, o serviço recusa subir com o erro nomeado, e a credencial da configuração é aceita pelo serviço externo enquanto a que estava no código é recusada. A segunda metade do aceite, a mensagem chegar ao contato quando existe uma linha ativa no serviço, permanece inobservável enquanto o {AUD-28} mantiver o canal estacionado e não houver instância pareada, exatamente como este card já registrava: o que está provado é que nenhuma credencial do produto fica escrita no código, e é o que esta entrega compra.
- Como verificar: conferir que nenhum dos três pontos carrega credencial escrita no código, apagando a credencial da configuração e vendo o serviço recusar-se a subir com erro nomeado, em vez de subir e despachar em silêncio com uma credencial que o canal recusa. E, com uma linha ativa no serviço do canal, exercitar o envio da automação e confirmar que a mensagem chega, provando pela entrega e não pela leitura.
- Aceite (H1): Dado o produto em produção, Quando se procura por credencial de acesso ao serviço do canal escrita no código, Então não existe nenhuma, nem como valor usado, nem como valor de reserva, E os três pontos que despacham pelo canal principal se identificam com o mesmo valor, lido da configuração, verificável porque apagar esse valor faz o serviço falhar na subida com erro nomeado em vez de despachar com credencial recusada, E, Dado uma linha ativa no serviço do canal, Quando a automação executa o passo de envio de whatsapp, Então a mensagem chega ao contato, E o passo só fica registrado como concluído quando a entrega de fato aconteceu.
- Prioridade: alta. É um produto autenticado, com contatos reais de clientes reais dentro, e as proteções que faltam são as que impedem que a página do sistema seja embutida em moldura de terceiro, que o conteúdo seja interpretado fora do tipo declarado, e que o navegador aceite descer para conexão não cifrada. RFs: RNF-010 (Perímetro autenticado), que hoje governa o perímetro do lado do servidor e não o do lado do navegador, e é por isso que este card também depende do {AUD-92}. Relacionado com o {AUD-26} e o {AUD-47}. Descoberto em 2026-07-16, na revisão de código do {AUD-89}.
- É dívida PRÉ-EXISTENTE, e isto precisa estar dito com todas as letras: o {AUD-89} não causou este defeito, não piorou este defeito e não tocou nele. O sistema nunca teve essas proteções, desde sempre. O {AUD-89} só passou perto o bastante para que alguém enfim olhasse.
- Contagem:
- Universo: 5. São as proteções de navegador que a casa já aplica nos seus outros sistemas, contadas pelo que o navegador de fato recebe naqueles sistemas, e não pelo que a configuração diz.
- Critério: comportamental. Abrir o sistema como um navegador abre e ler o que veio junto da resposta. Não é leitura de configuração: configuração que declara proteção e não entrega proteção é exatamente o caso descrito abaixo, e por isso ler configuração aqui é proibido como critério final.
- Placar: 0 proteções entregues / 5 ausentes / 0 mais 5 é igual a 5.
- Lado negativo, lido por inteiro: as 5 ausentes foram conferidas uma a uma na resposta que o sistema devolve hoje, em produção, e nenhuma delas veio.
- Controle positivo, e é ele que prova que o critério distingue de verdade: outros sistemas da casa, medidos pelo mesmo critério e no mesmo momento, entregam essas proteções ao navegador. O critério não é cego: ele acusa presença onde há presença.
- Universo de dados é 1 tenant: NÃO SE APLICA. A afirmação é sobre como o sistema é servido, e vale para todo mundo que o abre, seja qual for a empresa.
- Evidência de: 2026-07-16, medida na resposta de produção DEPOIS do {AUD-89} entregue, e não antes dele.
- Reprova por: o RNF-010 governa o perímetro, mas o verbo dele delimita: ele exige sessão válida e vínculo antes de qualquer efeito, e isso alcança o que o servidor aceita executar, não o que o navegador é instruído a proibir. Página do sistema embutida em moldura de terceiro não é "ator sem sessão disparando ação em nome de empresa", é a sessão legítima do próprio usuário sendo usada por quem ele não escolheu. Nenhum requisito publicado reprova o estado de hoje, e por isso este card também depende do {AUD-92}, que endurece o requisito para alcançar o perímetro do lado do navegador.
- A armadilha técnica que este card TEM que registrar, sob pena de o conserto virar um buraco pior que o defeito: pela mecânica do servidor, quando um trecho mais interno da configuração declara uma instrução de resposta própria, ele DESCARTA todas as instruções declaradas acima dele, em vez de somar. O {AUD-89} criou exatamente um trecho interno desses, para o arquivo de entrada. Então, no dia em que este card acrescentar as proteções no nível de cima, o arquivo de entrada, que é a página que o usuário de fato abre, vai perder todas elas em silêncio, e a medição de fora vai mostrar o sistema protegido em tudo menos justamente na página que importa. O conserto obrigatoriamente reinclui as proteções dentro daquele trecho.
- E isto não é hipótese, é o que já aconteceu na casa: outro sistema da casa declara essas proteções e entrega ZERO delas ao navegador, exatamente por esta mecânica, porque o trecho que serve as páginas dele declara instrução própria e descarta o resto. A configuração dele parece correta a olho nu e está publicando um sistema desprotegido. Ou seja, a armadilha deste card já capturou alguém, e a verificação por leitura de configuração é que não a viu. Este card só se dá por pronto medindo a resposta.
- O que fazer: acrescentar as proteções no nível de cima da configuração do sistema e, no mesmo trabalho e não depois, reincluí-las dentro do trecho do arquivo de entrada criado pelo {AUD-89}, de modo que a página que o usuário abre receba tanto a instrução de validade quanto as proteções.
- Como verificar: abrir o sistema como um navegador abre, em produção, e conferir na resposta as 5 proteções, e conferir no mesmo ato que a instrução de validade do {AUD-89} continua lá, provando que uma não apagou a outra. Medir na resposta, nunca na configuração: a configuração de outro sistema da casa prova que ela mente.
- Aceite (H1): Dado o sistema publicado em produção, Quando o navegador abre a página de entrada do sistema, Então as 5 proteções chegam na resposta, E a instrução de validade entregue pelo {AUD-89} continua chegando na mesma resposta, E o placar fecha: as proteções entregues são o conjunto inteiro, e as ausentes são nenhuma, verificável na resposta e não na configuração.
- Prioridade: alta, e é PAR do {AUD-90} e do {AUD-91}: sem este card, os dois são imortais. RFs: RNF-002 (Segurança de credenciais) e RNF-010 (Perímetro autenticado), que este card emenda. Descoberto em 2026-07-16, ao escrever os dois.
- O defeito é do documento e não do produto, e por isso este card vem ANTES do código dos outros dois. Nos dois casos o verbo delimita, e essa é a lacuna exata. O RNF-002 diz "segredos não aparecem em tela nem em log", e credencial escrita no código não é tela nem log, então o produto pode carregar credencial escrita no código para sempre sem violar linha nenhuma. O RNF-010 exige sessão válida e vínculo antes de qualquer efeito colateral, o que governa o que o servidor aceita executar, e não diz uma palavra sobre o que o navegador é instruído a proibir, então o sistema pode ser servido sem proteção nenhuma de navegador para sempre sem violar linha nenhuma.
- Por que isto é a mesma doença que a casa acabou de aprender duas vezes: requisito que não reprova nada não gateia nada. O {AUD-75} foi card imortal até o RF-AUTO-006 ser emendado, e o {AUD-83} tinha um quarto imortal até o {AUD-88} emendar o RF-CONV-054. Nos dois casos a correção foi no documento, e não no card. Aqui é idêntico, e em dobro: enquanto os requisitos não reprovarem, consertar o {AUD-90} e o {AUD-91} é opcional, e um dia alguém os fecha pela metade e nada acusa.
- O que fazer, e nos dois casos nomear o conjunto por PROPRIEDADE e não por lista, pela razão que o {AUD-88} já provou ser superior: enumerar deixa de fora o item que nascer amanhã, que é ser exaustivo por disciplina, o vício que o {AUD-65} existe para matar. No RNF-002, estender o alcance de onde o segredo não pode aparecer, de "tela e log" para todo lugar que não seja a configuração do ambiente, o que inclui o código do produto, e exigir que credencial ausente na configuração seja falha nomeada e não valor de reserva silencioso. No RNF-010, estender o perímetro para os dois lados: o que o servidor exige antes de agir, que já está escrito, e o que o produto instrui o navegador a proibir ao servir uma página autenticada, que não está.
- Como verificar: com os requisitos emendados, conferir que o {AUD-90} e o {AUD-91} têm no H1 um fato que os reprova pelo estado de hoje, e que nenhum dos dois passa no aceite sem ser feito.
- Aceite (H1): Dado o RNF-002 e o RNF-010 emendados, Quando o produto carrega uma credencial fora da configuração do ambiente, ou serve uma página autenticada sem instruir o navegador a proibir o que o produto não autoriza, Então o requisito reprova o estado, E o {AUD-90} e o {AUD-91} passam a ter requisito que os reprove, E nenhuma credencial futura e nenhuma página autenticada futura nasce fora do alcance dos requisitos.
- Prioridade: alta, porque é a mesma família de guarda que a casa acabou de decidir corrigir, e o RNF-006 já é violado hoje, independente de tráfego. RFs: RF-AGY-003 (Planos), RNF-006 (Observabilidade). Descoberto em 2026-07-16, durante a entrega da F2 do {AUD-65}, e é pré-existente: não foi causado por esta fatia, só apareceu no caminho dela.
- Sintoma: o teto mensal de execuções de automação por plano não confere se a própria contagem que ele faz respondeu com sucesso. Quando essa contagem falha, o resultado da comparação com o limite do plano fica indefinido, a comparação dá falso, e o teto deixa passar sem negar e sem registrar nada. Guarda que falha aberta em silêncio não protege, ela só produz a sensação de proteção, e isso é pior do que não ter proteção nenhuma.
- Por que nasce agora, e por que é da mesma família de um erro já descartado: é exatamente o vício que a F2 do {AUD-65} acabou de corrigir na guarda nova, que também se contornava sozinha quando a própria medição dela falhava. A casa acabou de decidir, na mesma entrega, que falhar fechado é o padrão em guarda de segurança, e este teto mais antigo do plano ainda falha aberto. É a mesma família do defeito já tratado no {AUD-84}, uma guarda que decide pelo estado errado quando a leitura que a sustenta não responde do jeito esperado.
- Como verificar: reprova antes de tocar em código, forçando de propósito a contagem de execuções do mês a falhar numa empresa com automação ativa, e confirmando que uma execução nova passa mesmo assim, sem nenhum registro do motivo. Depois do conserto, a mesma falha forçada precisa negar a execução e registrar o motivo nomeado, e uma empresa dentro do limite continua executando normalmente.
- Aceite (H1): Dado a contagem de execuções do mês falhando por erro real, e não por atingir o teto, Quando o motor decide se libera a próxima execução, Então ele nega por padrão, E registra o motivo nomeado da negativa, E nenhuma execução passa enquanto essa contagem não responder com sucesso.
- Prioridade: alta, e não pelo tamanho do placar: pelo consumidor. O liga-desliga da cobrança é lido de verdade por uma rotina automática, então existe regra de negócio real obedecendo hoje um valor que o administrador não consegue mudar pela tela. Requisito que reprova: RNF-008 (Editável pela operação). Descoberto em 2026-07-16, no caminho da F2 do {AUD-65}, e é pré-existente: não foi causado por aquela fatia. Não confundir com ela, que já está entregue: aquela acrescentou UMA chave à lista; este card ataca a razão de a lista existir.
- Sintoma: a tela geral de configurações decide como validar cada campo consultando uma lista de tipos declarados. Quando a configuração não está nessa lista, a tela cai num padrão que assume TEXTO. Valor que não é texto é recusado por esse padrão, o envio nem chega a acontecer, e o controle de liga-desliga não exibe erro nenhum: o administrador mexe o controle, clica em salvar, e não acontece nada. Sem erro, sem aviso. É a mesma doença que a Onda AUD vem corrigindo: a tela finge que aceitou.
- Por que é grave, e são os dois lados: não é configuração morta dos dois lados, é pior de outro jeito. O liga-desliga da cobrança tem consumidor real: uma rotina automática o lê para decidir se os avisos de cobrança saem para os clientes. A única forma de mudá-lo hoje é mexer direto no banco, que é exatamente o que o RNF-008 proíbe. Do outro lado, a exibição dos eventos do calendário externo é editada também por uma SEGUNDA tela, que salva por caminho próprio e não passa por este padrão: a mesma configuração aparenta estar viva lá e morta aqui.
- O que ainda NÃO foi confirmado, e é o primeiro passo do conserto: nada disto foi exercitado na tela real. O defeito foi lido no código e os tipos foram medidos no banco, o que prova a fiação, não o comportamento. Reproduzir na tela vem antes de tocar em qualquer linha. Vale em especial para a segunda tela do calendário: medir tela a tela, sem presumir que o defeito é o mesmo nas duas. E o dano às cinco configurações numéricas é latente, não observado: as cinco ainda estão gravadas com o tipo certo, ou seja, ninguém as editou pela tela até hoje. Nunca falhou e nunca rodou são indistinguíveis aqui.
- Contagem (o placar fecha, e o número que abriu este card estava errado nos DOIS sentidos). Universo: 49 configurações, contadas por consulta ao banco, não por busca no código. Critério, comportamental: a tela submete a chave E quem decide sobre ela é o padrão (porque a chave não está na lista) E o valor gravado não é texto; ou seja, o padrão decide e decide errado. Placar: 7 quebradas, 42 sãs, 7 mais 42 igual a 49. As 7 se partem em dois sintomas diferentes: 2 configurações de liga-desliga são recusadas em silêncio e não salvam (o liga-desliga da cobrança e a exibição dos eventos do calendário externo), e 5 configurações numéricas salvam, porém gravam o valor com o tipo trocado para texto (a antecedência do aviso de renovação, a validade do link de remarcação, o limite de novas tentativas do envio de eventos de anúncio, o tamanho do código do link curto e o tempo de retenção dos links de disparo). Lado negativo, lido por inteiro: (a) a chave geral do motor de automação tem validação própria declarada na lista e por isso não cai no padrão, e é o controle positivo deste card, porque foi acrescentada hoje, na F2 do {AUD-65}, exatamente porque o gate previu esta armadilha; (b) o remetente dos emails de cobrança está FORA da lista e mesmo assim funciona, porque o valor dele É texto e o padrão acerta por coincidência, o que prova que a ausência na lista sozinha não quebra nada, quebra a ausência CRUZADA com o tipo não-textual; (c) as 4 estruturas e as 2 listas (a estrutura da cobrança, os modelos de email de cobrança, os textos da janela de pagamento, as faixas de pontuação do contato, a agenda de lembretes de cobrança e os intervalos de nova tentativa do envio de eventos de anúncio) NÃO são este defeito e por isso saíram da conta: a tela devolve essas seis antes do formulário, em modo somente leitura, com aviso na própria interface de que hoje se editam pelo banco. É limitação declarada, não falha muda. Universo é 1 tenant? Não: a tabela de configurações não tem coluna de empresa, é configuração global do produto, então o universo de 49 é o conjunto inteiro e cabe dizer "todas". Evidência de: 2026-07-16, contra o estado de hoje, já incluído o commit da F2 do {AUD-65}; o controle positivo é a prova de que a evidência é posterior ao fix citado, e não anterior.
- Por que o número anterior (oito) estava errado, e a lição vale para as próximas auditorias: ele contou por TIPO (valor não-textual ausente da lista) e não por COMPORTAMENTO (o padrão decide e erra). Com isso incluiu as 6 que a tela nem edita e que avisam o administrador na cara, e perdeu as 5 numéricas, que o padrão de fato valida, aceita e corrompe. Os dois erros andaram juntos e quase se anularam no total, que é o jeito mais traiçoeiro de um placar mentir. É a mesma falha do {AUD-65} e do {AUD-43}: critério que olha o símbolo em vez do que o ponto FAZ.
- A raiz, e é ela que este card entrega, não os remendos: o padrão que assume texto é uma armadilha por desenho. Toda configuração não-textual nova nasce morta, e ninguém percebe, porque a tela não reclama. Acrescentar as chaves de hoje à lista é ser exaustivo por disciplina, e a próxima nasce morta amanhã, exatamente como esta nasceu. A regra da casa manda decidir a raiz antes dos N remendos: o padrão passa a respeitar o tipo do valor já gravado (valor de liga-desliga exige validação de liga-desliga, número exige número, e assim por diante), de modo que a configuração nova entre certa por existir, e não por alguém ter lembrado de cadastrá-la.
- A armadilha do conserto óbvio, e ela é pior que o defeito: a conversão automática de texto para liga-desliga NÃO serve aqui, porque ela trata o texto "false" como verdadeiro. Adotá-la tornaria impossível DESLIGAR qualquer coisa pela tela, e o defeito viraria irreversível em vez de mudo. O conserto tem que exigir o tipo certo, nunca converter às cegas.
- Terceira parte, sem a qual as outras duas voltam: o controle de liga-desliga precisa exibir o erro de validação no próprio campo, como os campos de texto já fazem. Falhar mudo é o que permitiu este defeito sobreviver, e é o que vai esconder o próximo.
- Como verificar (reprova ANTES de tocar em código): na tela real, mexer o liga-desliga da cobrança e salvar, e confirmar que nada é gravado e que nenhum erro aparece; conferir na segunda tela do calendário se a mesma configuração salva por lá, medindo as duas telas em vez de presumir; e alterar uma das cinco numéricas pela tela e conferir que o valor gravado mudou de tipo. Depois do conserto: as duas de liga-desliga salvam e o valor gravado muda de verdade; as cinco numéricas salvam mantendo o tipo; um valor recusado exibe o motivo no campo, inclusive no liga-desliga; uma configuração não-textual NOVA, criada sem ninguém cadastrá-la em lista nenhuma, é editável e salva de primeira; e desligar de fato desliga, sem que o texto "false" seja lido como ligado.
- Aceite (H1): Dado uma configuração cujo valor gravado não é texto e que não tem validação própria declarada, Quando o administrador a altera na tela geral e salva, Então o valor é aceito e gravado com o mesmo tipo que já tinha, E uma configuração não-textual criada depois deste card passa a ser editável sem que ninguém precise cadastrá-la em lista nenhuma, E toda recusa de validação aparece no próprio campo, inclusive no controle de liga-desliga, E desligar um liga-desliga pela tela realmente o desliga.
- Prioridade: alta, e é pré-requisito do {AUD-94}. PAR obrigatório dele, exatamente como o {AUD-88} nasceu par do {AUD-83} e como a emenda do RF-AUTO-006 foi pré-requisito do código do {AUD-75}. Requisito a emendar: RNF-008 (Editável pela operação). Nasceu em 2026-07-16, na publicação do {AUD-94}, e não é achado novo de produto: é defeito do documento, encontrado ao perguntar qual requisito reprova aquele card.
- Por que este card existe, e é a razão inteira do par: H1 de card morre quando o card fecha; requisito, não. Fechado o {AUD-94}, o texto que impede a próxima configuração de nascer morta tem que estar no RNF-008, senão ele fecha junto com o card e o defeito volta pela mesma porta. Sem esta emenda, um pedaço do {AUD-94} é imortal: ninguém o reprova, então ninguém é obrigado a mantê-lo consertado.
- Lacuna 1, a raiz não é gateada: o RNF-008 de hoje promete que nada exige mexer no banco para mudar configuração de negócio. Ele reprova cada chave morta reativamente, uma a uma, no dia em que alguém descobre que aquela só muda pelo banco. Ele não exige, em lugar nenhum, que a tela decida a validação pelo tipo do valor guardado. Então nada impede a próxima configuração não-textual de nascer morta amanhã, e o requisito só vai reclamar dela depois que alguém a encontrar. É a diferença entre exaustivo por construção e exaustivo por disciplina, e é a mesma doença que o {AUD-65} inteiro existe para matar.
- Lacuna 2, a falha muda não é gateada por nada: o administrador mexe o controle, salva, e não acontece nada, sem erro e sem aviso. Nenhum requisito reprova isso hoje. O RNF-006 trata de registro de auditoria e rastreamento de erro, que é o sistema guardar o que aconteceu, e não a tela avisar o administrador na hora. Procurado o requisito que reprova "a tela recusou e não disse", não existe.
- E a falha muda tem DOIS sintomas opostos, então a emenda tem que reprovar os dois: recusar em silêncio (as duas de liga-desliga, que não salvam) e aceitar gravando errado (as cinco numéricas, que passam e são guardadas com o tipo trocado). Requisito que só exija "avisar quando recusa" deixa metade viva, e é justamente a metade que ninguém vê, porque ela responde sucesso.
- Contagem (é sobre o que o REQUISITO alcança, e não sobre o que o código faz). Universo: as 7 configurações quebradas do placar do {AUD-94}, medidas em 2026-07-16 por consulta ao banco, e não por busca no código. Critério, comportamental: ler o RNF-008 de hoje ao pé da letra e completar a frase "este requisito é violado quando ___" com o defeito de cada uma; a promessa dele é que nada exige mexer no banco para mudar configuração de negócio, então a pergunta é se o defeito daquela configuração empurra o administrador para o banco. Placar: 2 reprovadas, 5 não reprovadas, 2 mais 5 igual a 7. Lado negativo, lido por inteiro: as cinco numéricas (a antecedência do aviso de renovação, a validade do link de remarcação, o limite de novas tentativas do envio de eventos de anúncio, o tamanho do código do link curto e o tempo de retenção dos links de disparo). Nenhuma das cinco é reprovada, e o motivo é o mesmo nas cinco: elas TÊM tela de edição, e o administrador as muda por lá sem nunca ir ao banco, então as duas promessas do texto de hoje passam. Que o valor seja guardado com o tipo trocado é assunto sobre o qual o RNF-008 é literalmente silencioso, e silêncio não reprova. Universo é 1 tenant? Não: a tabela de configurações não tem coluna de empresa, é configuração global do produto, o mesmo fato que o {AUD-94} mediu. Evidência de: 2026-07-16, contra o texto do RNF-008 publicado hoje e contra o placar do {AUD-94}, que é card aberto e não entregue, então não há risco de a evidência ser anterior a um conserto. Reprova por: nenhum requisito, e é exatamente esse o achado. Este card é a metade de requisito do par e o {AUD-94} é a metade de código; a regra da casa proíbe deixar "exige requisito novo" solto, e por isso o par nasce irmanado em vez de virar bilhete.
- DECISÃO sobre as seis configurações que a tela devolve em modo leitura (a estrutura da cobrança, os modelos de email de cobrança, os textos da janela de pagamento, as faixas de pontuação do contato, a agenda de lembretes de cobrança e os intervalos de nova tentativa do envio de eventos de anúncio): elas NÃO são excetuadas. São dívida declarada do RNF-008, e já eram antes desta emenda. Quatro motivos, e o terceiro é o que decide.
- Motivo 1, não há atropelo: lido ao pé da letra, o RNF-008 de HOJE já as reprova, porque elas exigem mexer no banco para mudar configuração de negócio, que é textualmente o que a promessa proíbe. A emenda não as transforma em violação por acidente; ela torna visível uma violação que o texto de hoje já produz. O {AUD-94} as excluiu do placar DELE com razão, porque não são o mesmo defeito, e excluir do placar de um card nunca foi o mesmo que excluir do alcance de um requisito.
- Motivo 2, excetuar seria enumerar: "exceto as seis que hoje são somente leitura" é uma lista, e lista envelhece no dia em que nasce a sétima. Enumerar é a doença exata que esta emenda existe para matar, e ela não pode nascer cometendo-a.
- Motivo 3, e é o que decide: excetuar "somente leitura com aviso" como cumprimento cria uma saída trivial. Qualquer configuração passaria a cumprir o RNF-008 bastando virar somente leitura e ganhar um aviso; o aviso viraria o conserto, e o requisito deixaria de reprovar aquilo para o que existe. Requisito que nada reprova é o defeito que este par inteiro combate.
- Motivo 4, o que de fato separa as seis do {AUD-94}: as duas situações violam a mesma promessa, e só uma engana. Limitação declarada e visível é honesta, porque o administrador sabe onde está e sabe o que fazer. Falha muda é desonesta, porque ele acha que salvou. Por isso a emenda separa os DESFECHOS em vez de separar as configurações: a falha muda é proibida sem prazo, e a limitação declarada é dívida com prazo em aberto, que enquanto durar tem que continuar declarada e visível na tela.
- Destino da dívida, registrado para não virar bilhete: não é o {AUD-94}, e ele não deve absorvê-la. É frente aberta do RNF-008, hoje sem card, e fechá-la é decisão de produto que ainda não foi tomada: construir a edição das seis, ou reduzir a promessa de propósito, o que exigiria emendar o RNF-008 para baixo, e quem baixa promessa é que precisa de aprovação. Registrar a dívida no próprio requisito é o estado correto do documento; chamá-la de exceção seria o requisito baixando a promessa sozinho, sem ninguém decidir.
- O TEXTO DA EMENDA (é isto que vai para o RNF-008, preservando a frase de abertura que já existe e acrescentando as três regras, o aceite e o estado):
- Regra do alcance da validação (é propriedade, e é ela que gera o conjunto, nunca uma lista): a tela que edita configuração decide como validar cada uma a partir do tipo do valor que já está guardado, e nunca a partir de um cadastro de configurações mantido à mão. A propriedade é a única condição: se a configuração existe e a tela a oferece, ela está no alcance, e nada mais a exclui. Configuração nova entra no alcance por existir, e não por alguém ter lembrado de cadastrá-la. Cadastro mantido à mão envelhece no dia em que nasce a configuração seguinte, e é por isso que ele não vale como mecanismo aqui: o que vale é o tipo do valor, que a própria configuração já carrega consigo.
- Regra do desfecho da edição (são dois desfechos, e nunca um terceiro): toda edição enviada pela tela termina de uma destas duas formas, e de nenhuma outra. Ou o valor é válido, e então ele é gravado de verdade, com o mesmo tipo que a configuração já tinha, e passa a valer para quem consome aquela configuração. Ou o valor é inválido, e então o administrador vê o motivo nomeado no próprio campo que recusou, na hora em que tenta salvar. Recusar sem dizer é proibido, seja qual for o tipo do campo, e vale igual para o controle de liga-desliga e para o campo de texto: diante de uma edição, silêncio é sempre defeito, porque o administrador não tem como distinguir "recusei" de "gravei". Aceitar e gravar diferente do que foi pedido é proibido pela mesma regra, e é a mesma falta pelo avesso: o valor gravado nunca muda de tipo por causa da tela. Converter às cegas é proibido, e mais ainda quando a conversão inverte o sentido: valor que significa negação nunca é lido como consentimento.
- Regra da limitação declarada (é dívida deste requisito, nunca exceção a ele): configuração que a tela ainda não deixa editar é dívida declarada deste requisito, e não cumprimento dele. Enquanto a dívida durar, a tela mostra a configuração em modo leitura, com o motivo e o caminho alternativo nomeados na própria interface, para o administrador saber onde está. Declarar reduz o dano e não quita a promessa: modo leitura com aviso nunca conta como "tem tela de edição". Esta regra existe para que a honestidade da tela não vire a saída fácil do requisito: se bastasse avisar, qualquer configuração cumpriria este requisito virando somente leitura, e ele deixaria de reprovar aquilo para o que existe.
- Aceite do requisito emendado (H1): Dado uma configuração de negócio que a tela oferece para edição, Quando o administrador a altera e salva, Então ou o valor é gravado com o mesmo tipo que já tinha e passa a valer para quem o consome, ou a recusa aparece com o motivo nomeado no próprio campo, e nunca um terceiro desfecho; E, Dada uma configuração não-textual criada depois desta emenda, Quando o administrador a edita pela primeira vez, Então ela é editável e grava de primeira, sem que ninguém a tenha cadastrado em lista alguma; E, Dado um valor que significa negação, Quando ele é gravado pela tela, Então quem o consome o lê como negação; E, Dado o conjunto das configurações de negócio do produto, Quando esse conjunto é levantado por construção, a partir do que está guardado, e não por lista mantida à mão, Então nenhuma delas exige mexer no banco para ser mudada, E o placar fecha: as que a tela edita de verdade são o conjunto inteiro e as que só o banco muda são nenhuma, sendo que cada uma que ainda só o banco muda é dívida declarada e visível na tela, e conta contra este requisito enquanto durar.
- O estado honesto a registrar junto com a emenda (é o estado CORRETO do documento, e não um defeito dela): com o requisito endurecido, o RNF-008 passa a estar violado em produção em duas frentes, e a nota do requisito tem que dizer isso pelo nome. Frente 1, a recusa muda e o tipo trocado, que o {AUD-94} fecha, e enquanto ele não fechar o requisito está violado ali. Frente 2, as seis configurações que a tela só devolve em modo leitura, que são dívida declarada e seguem sem card. Quem alcança o requisito é o produto, não é o requisito que baixa a promessa, e é assim que o RF-AUTO-006, o RF-AUTO-044 e o RF-CONV-054 já se registram neste documento.
- O que fazer no Plano de Testes, e a parte de conferir já foi feita: a emenda NÃO torna nenhum item marcado como validado uma mentira. Conferido item a item em 2026-07-16: nenhum item marcado cobre o RNF-008, e o Plano de Testes não cita este requisito em lugar nenhum. O que a emenda revela é a ausência: o RNF-008 é requisito endurecido sem item de teste próprio, enquanto o RNF-002 e o RNF-006 têm o seu. Executar este card inclui abrir o item Alfa do RNF-008, cobrindo os dois desfechos da edição, a configuração não-textual nova que entra por existir, o valor de negação que é lido como negação, e a dívida declarada que continua visível na tela.
- Como verificar (é documento, então a verificação é de texto, e ela reprova ANTES): antes da emenda, procurar no RNF-008 o que reprova "a tela recusou a edição e não avisou" e o que reprova "a próxima configuração não-textual nasce morta", e confirmar que não há nada dos dois. Depois da emenda: o RNF-008 publicado contém as três regras e o aceite acima; a regra do alcance é formulada por propriedade e não cita nenhuma configuração pelo nome; a nota do requisito registra as duas frentes de violação em produção; a página do documento responde e o requisito aparece com o texto novo; o Plano de Testes ganha o item Alfa do RNF-008; e o {AUD-94} passa a ter requisito que o reprove nas três partes, e não só na primeira.
- Aceite (H1): Dado o RNF-008 emendado e publicado, Quando alguém pergunta qual requisito reprova cada uma das três partes do {AUD-94}, Então o RNF-008 responde pelas três (a raiz, a recusa muda e o aceite que grava errado), E a resposta não depende de nenhuma configuração estar cadastrada em lista alguma, E, Quando o {AUD-94} fechar, Então o texto que impede a próxima configuração de nascer morta continua de pé, porque ele vive no requisito e não no card.
- Prioridade: média, latente hoje porque nenhuma empresa usa o canal alternativo. RFs: RF-AUTO-044 (honestidade do registro de execução) e RF-CONV-054 (honestidade do envio). Relacionado com o {AUD-83}, que criou o lugar único e serviu o canal alternativo por premissa de propósito, e com o {AUD-42}, de quem é a mesma doença: decidir pela premissa em vez do resultado. Descoberto em 2026-07-17, na verificação do {AUD-83}, um achado do qa e um risco nomeado no planejamento.
- O defeito, e são duas pontas do mesmo canal: (a) o lugar único responde utilizável para uma empresa de canal alternativo quando as credenciais existem, sem sondar nada, e devolve o nome de instância nulo, porque o canal alternativo não tem instância no serviço principal; três dos quatro despachantes usam esse nome de instância nulo numa chamada ao serviço principal, e o motor de automação produziria desfecho de falha, que o RF-AUTO-044 proíbe. (b) O envio pelo operador do canal alternativo está estruturalmente morto para qualquer usuário, porque a resolução de empresa do endereço consulta uma coluna que não existe na tabela de perfis, e a chamada é recusada antes de chegar ao lugar único; é defeito pré-existente, confirmado também fora desta fatia. Nota (2026-07-17, fatia {AUD-32}): os endereços de envio e de configuração do canal alternativo ganharam o auxiliar de impersonate do Super Admin; ele fica inerte enquanto a resolução de empresa recusar pela coluna inexistente, e passa a valer quando este card religar as pontas.
- Contagem:
- Universo: 4. São os despachantes de whatsapp do {AUD-83}, contados pelo despacho de saída, e não pelo símbolo do envio.
- Critério: comportamental. Ao receber utilizável do lugar único para uma empresa de canal alternativo, que devolve nome de instância nulo, o despachante chama o serviço principal com esse nome nulo, ou segue pelo caminho próprio do canal alternativo.
- Placar: 3 chamam o serviço principal com o nome nulo (a rotina de lembrete, o robô de conversa e o motor de automação) / 1 segue pelo caminho próprio do canal alternativo (o operador pela tela) / 3 mais 1 é igual a 4. Dos 3, o motor produziria desfecho de falha, proibido pelo RF-AUTO-044.
- Lado negativo, lido por inteiro: o operador pela tela é o único que não usa o nome de instância para o serviço principal. Ele ramifica pelo tipo de canal, exige que a empresa seja de canal alternativo e chama o serviço próprio do canal alternativo com as credenciais dele, nunca o serviço principal. E esse mesmo caminho está morto pela ponta (b): a resolução de empresa consulta a coluna inexistente e recusa antes de qualquer envio.
- Universo de dados é 0 empresas de canal alternativo: SIM, e por isso este card NÃO diz que quebra empresas hoje. Nenhuma empresa usa o canal alternativo; a única com configuração de whatsapp gravada usa o canal principal. O defeito é do código, latente até a primeira empresa escolher o canal alternativo.
- Evidência de: 2026-07-17, no código em produção do merge aca9db6, medido pelo qa (a coluna inexistente confirmada por consulta ao banco, com a mensagem de erro da própria consulta) e pela leitura por inteiro dos quatro despachantes.
- Reprova por: RF-AUTO-044, na Regra da empresa sem canal conectado, que exige passo ignorado com motivo nomeado e nunca falha, e no trecho do H1 que aceita passo ignorado por ausência de canal, mas nunca falha por esse motivo: o motor produziria falha para a empresa de canal alternativo. E RF-CONV-054, no invariante literal do H1 “nunca chamar o canal externo com o canal não utilizável”: o lugar único declara utilizável por premissa um canal cujo envio próprio está morto, e manda três despachantes ao canal errado.
- O que fazer: o lugar único, para uma empresa de canal alternativo, ou sonda a utilizabilidade real do canal alternativo em vez de decidir pela premissa das credenciais, ou devolve um veredito que os três despachantes do serviço principal saibam recusar sem chamar o serviço errado com nome nulo; e a resolução de empresa do endereço de envio do canal alternativo passa a ler a coluna que existe, para o operador voltar a poder despachar. Empresa de canal alternativo nunca gera chamada ao serviço principal nem desfecho de falha por esse motivo.
- Como verificar: com uma empresa configurada no canal alternativo, exercitar os três despachantes do serviço principal e confirmar que nenhum chama o serviço principal com nome de instância nulo, e que o motor não registra falha; e exercitar o envio do operador pela tela e confirmar que a resolução de empresa não é recusada pela coluna inexistente.
- Aceite (H1): Dado uma empresa configurada no canal alternativo de whatsapp, Quando qualquer despachante do produto tenta enviar por ela, Então nenhum chama o serviço externo do canal principal, E o passo de automação nunca fica registrado como falha por causa do canal alternativo, E o envio do operador pela tela alcança o lugar único sem ser recusado por uma coluna inexistente na resolução de empresa.
- Prioridade: média, pré-existente e independente do {AUD-83}. RFs: RF-CONV-025 (bot de conversa com modos de resposta) e RNF-006 (observabilidade). Relacionado com o {AUD-83}, em cuja verificação o robô de conversa apareceu barrado. Descoberto em 2026-07-17, achado do qa.
- O defeito: a resposta automática de IA do robô de conversa depende de uma chave de modelo de linguagem lida da configuração do ambiente, e essa chave está ausente em produção. Sem ela, o robô retorna cedo e não responde, e o único registro é uma linha de log técnico que ninguém acompanha: não há aviso por empresa, não há sinal na tela, e o administrador que liga o Piloto Automático de uma empresa acredita que o robô responde, e ele não responde. É a mesma doença que a Onda AUD vem corrigindo: o produto finge um estado que não tem.
- Alcance (é global por construção, não amostra): a checagem da chave roda antes de qualquer empresa ser carregada, e a função retorna nesse ponto, então o efeito é o mesmo para toda empresa que usaria a resposta automática, por construção, e não por contagem de empresas.
- Por que a chave global também contradiz o modelo do produto: o produto foi decidido no modelo traga sua própria chave, com IA gratuita padrão bancada pela casa e opção de o cliente ativar IA paga com a própria chave, por empresa, isolada e cifrada. Ler a chave de uma configuração global do ambiente não é esse modelo, e a ausência dela derruba a IA gratuita padrão de todo mundo de uma vez.
- Reprova por: RNF-006, no trecho “a origem de cada evento é identificável” e no rastreamento de erro por empresa, que a falha muda global viola; e RF-CONV-025, no trecho do H1 “ao trocar o modo para Autopilot o bot passa a responder automaticamente”, que fica prometido e mudo enquanto a chave da IA gratuita padrão não existir.
- O que fazer: tornar observável, por empresa e na tela de quem liga o Piloto Automático, o estado de a resposta automática estar indisponível por falta de chave, em vez de falhar em silêncio; e alinhar a origem da chave ao modelo traga sua própria chave, por empresa, em vez de uma única chave global do ambiente. Se a intenção é que a IA gratuita padrão exista, a chave dela precisa estar configurada; se não, o estado desligado precisa ser dito, nunca silencioso.
- Como verificar: com a chave ausente, ligar o Piloto Automático de uma empresa e confirmar que o produto informa que a resposta automática está indisponível, em vez de aceitar em silêncio; com a chave presente, a resposta automática funciona.
- Aceite (H1): Dado que a resposta automática de IA está indisponível por falta de chave, Quando o administrador liga o Piloto Automático de uma empresa, Então o produto informa o estado indisponível de forma observável, por empresa, E nenhuma empresa fica com o robô prometido e mudo sem que nada o registre.
- Prioridade: média, dívida nomeada e sem urgência porque a decisão do canal não depende dela: o lugar único do {AUD-83} sonda ao vivo e não lê esta telemetria. RFs: RNF-006 (observabilidade). Relacionado com o {AUD-83}, que decidiu não ler estas colunas exatamente por causa desta dívida. Descoberto em 2026-07-17, na emenda do planejamento do {AUD-83} com o serviço externo na conta.
- O defeito: existe um serviço que ouve os eventos do canal e escreve, em tempo real, o estado da instância e o motivo da última queda, casando pelo nome da instância. Ele é puramente reativo: não confere periodicamente se a instância ainda existe, não reverte o estado quando ela some, e não carimba um pulso. Quando a instância desaparece do serviço externo, ele fica mudo, e a linha congela no último estado que viu. Medido: a linha do tenant piloto está congelada há mais de dois meses, dizendo um estado que não corresponde a uma instância que não existe mais. Se o último evento tivesse sido conectado e a instância fosse apagada por fora, a linha ficaria dizendo conectado para sempre, um falso positivo, que é a única direção que o invariante do canal proíbe.
- Por que não é urgente, e por que mesmo assim é dívida: não é urgente porque nada no produto lê esta telemetria para decidir se despacha, desde o {AUD-83}. É dívida porque o papel legítimo dessas colunas é telemetria e tela (mostrar por que um canal caiu), e telemetria que mente por vencimento engana quem a lê na tela tanto quanto um estado errado enganaria a decisão. Enquanto o serviço não reconciliar nem tiver pulso, essas colunas não servem para decisão nenhuma, o que reforça a sonda ao vivo do {AUD-83}.
- Reprova por: RNF-006, no trecho “há rastreamento de erros; a origem de cada evento é identificável”: o desaparecimento da instância nunca vira evento, então a queda do canal fica sem rastro e a tela pode apresentar um estado vencido como se fosse atual.
- O que fazer: o serviço passa a reconciliar periodicamente contra a lista de instâncias do serviço externo, revertendo o estado quando a instância some, e a carimbar um pulso para que a idade da linha distinga um canal conectado e ocioso de um canal morto e congelado. Feito isso, a telemetria da tela deixa de mentir por vencimento.
- Como verificar: apagar por fora uma instância cujo último estado foi conectado e confirmar que o serviço reverte o estado em vez de deixar a linha dizendo conectado para sempre; e conferir que a idade da linha anda por pulso, distinguindo instância ociosa de instância morta.
- Aceite (H1): Dado uma instância cujo último estado registrado é conectado, Quando ela deixa de existir no serviço externo, Então a telemetria do canal deixa de dizer conectado dentro de um intervalo previsível, E a idade da linha distingue um canal conectado e ocioso de um canal morto e congelado, E nenhuma tela do produto apresenta como conectado um canal que não existe mais.
- Prioridade: baixa e condicional hoje, sobe quando a chave geral ligar com tenant real. RFs: RNF-003 (confiabilidade da entrega assíncrona). Descoberto em 2026-07-17, como consequência declarada da F4 do {AUD-65} (a remoção dos emissores antigos tirou o cinto e suspensório da janela de perda). O gate da F3 já listou este card como gatilho explícito, na seção 8, condição c.
- O defeito, e ele é de desenho e não de implementação: o gatilho no banco notifica um canal e o ouvinte só recebe se estiver escutando naquele instante. Se o processo de saída estiver fora do ar quando um contato é inserido, o banco descarta o aviso e a reconexão do ouvinte não reproduz o que passou. O evento se perde em silêncio. Enquanto os cinco emissores antigos existiam, eles eram redundância para os seus caminhos; a F4 os removeu, então agora todo caminho de criação depende unicamente do salto gatilho até ouvinte, sem rede.
- Contagem (o placar do risco, medido e não estimado):
- Universo: a janela de perda é o intervalo em que o processo de saída está fora do ar E um contato é inserido. Contada por dois fatos independentes, não pelo mesmo símbolo: o tempo de indisponibilidade do processo e o volume de inserção de contato.
- Critério, comportamental: a perda ocorre quando processo fora do ar e inserção em contacts coincidem no tempo; o T4b da F3 provou que nessa coincidência o run NÃO nasce.
- Placar: o processo de saída está no ar há dias e reconecta em cinco segundos por keepalive; o tráfego real de contato mede zero na Hiit desde 2026-05-22 e um punhado por mês na única organização com automação. A probabilidade de coincidência hoje é próxima de zero, e é por isso que o card nasce de prioridade baixa, não porque o defeito não exista.
- Lado negativo, lido por inteiro: a durabilidade DEPOIS do enfileiramento JÁ está resolvida (T4a, o trabalho na fila sobreviveu a quatro quedas e a execução nasceu uma vez só); o defeito é só o trecho ANTES do enfileiramento, o salto gatilho até ouvinte. E o próprio ouvinte confessa esse limite no cabeçalho do arquivo (notify-listener.js, linhas 11 e 12).
- Universo é 1 tenant? Não: vale para todo caminho de criação de contato de qualquer organização, porque o gatilho é do banco inteiro.
- Evidência de: 2026-07-17, contra o estado com a F3 e a F4 já mergeadas (main e4032e6); o T4b é a prova viva de que o run não nasce na janela.
- Reprova por: RNF-003, na cláusula de confiabilidade da entrega assíncrona; o salto sem caixa de saída deixa um evento cair sem rastro, e a promessa de entrega confiável não se cumpre para o contato inserido durante a janela.
- O que fazer: gravar o intento numa tabela de caixa de saída na MESMA transação que insere o contato, e trocar o aviso puro por um consumidor que faz reserva (claim) dessa tabela, de modo que o evento sobreviva à queda do processo. Prioridade condicional: baixa enquanto o tráfego real for próximo de zero; sobe quando houver tenant real na lista de organizações permitidas, ou quando o rastreamento de perda registrar um caso. Atualização de 2026-07-17: a chave geral foi LIGADA sob observação, então este card sobe de patamar como o próprio card previa, mas o gatilho real de prioridade continua sendo tenant real na lista de permitidas, que ainda não há (só a organização de teste), e por isso a prioridade efetiva segue baixa por ora.
- Como verificar: derrubar o processo de saída, criar um contato durante a queda, subir o processo, e confirmar que o run NASCE (hoje, com o T4b, ele NÃO nasce).
- Aceite (H1): Dado o processo de saída fora do ar, Quando um contato é inserido durante a queda, Então ao subir o processo o run daquele contato nasce, E nenhum evento de criação se perde por causa da janela do salto gatilho até ouvinte.
- Reconciliado em 2026-07-22 (council GO): a mesma caixa de saída transacional deste card passa a ser reusada pela captura de leads Meta (enriquecimento retido até reconectar, {C-MCRM-4}). O padrão é o mesmo (gravar o intento na mesma transação, consumidor com reserva); a prioridade da captura de leads é P1 core, então a construção da caixa de saída pode ser puxada por {C-MCRM-4} antes deste card de automação. Sem tabela única cross-produto: cada uso instancia o padrão no seu domínio.
- RESOLVIDO em 2026-07-17. Medição achou uma instância afetada, o passo 054bbb3a do workflow "Welcome + Tag" da organização de teste da Modulareasy (a Hiit ficou ilesa, tem zero workflows). A tag "novo" não existia na organização e foi criada (identificador 42d6bcc3), a configuração do passo foi resolvida do nome legado para o identificador da tag, e o script ficou registrado em migrations/data-fixes/2026-07-17_aud100-resolve-tag-id.sql (commit 0983627). O H1 foi PROVADO por comportamento: com a chave geral ligada, um contato de prova disparou o "Welcome + Tag", que completou e APLICOU a tag de verdade (execução c0c05d3c), a primeira execução com efeito real na história do motor.
- Prioridade: média. RFs: RF-AUTO-003 (Ações), RF-AUTO-006 (Modelos de automação). Descoberto em 2026-07-16 e revisto em 2026-07-17, no qa das fatias F3 e F4 do {AUD-65}; é pré-existente, não foi causado por elas.
- Sintoma: o passo de adicionar tag do workflow "Welcome + Tag" da organização de teste falha em produção com o erro nomeado "add_tag: configuracao invalida (tag_id ausente, talvez tag_name legado sem resolver)", visto pelo qa nas duas fatias. O defeito começou a aparecer em 2026-07-16, quando o {AUD-68} passou a derivar o desfecho real do passo, e é pré-existente àquela data.
- Causa: o {AUD-75} consertou o MODELO, de modo que deploys novos gravam o identificador da tag em vez do nome; mas ele não migrou as INSTÂNCIAS que já existiam. Os passos de automação criados antes carregam o nome da tag no lugar do identificador, e o motor, que hoje é honesto (RF-AUTO-044), reprova a configuração inválida em vez de fingir sucesso. O erro é o motor certo reprovando uma instância legada errada.
- O que fazer: migrar a configuração dos passos de automação existentes que ainda têm o nome legado da tag, resolvendo o nome para o identificador (e criando a tag se ela não existir, ou falhando com o motivo nomeado se a resolução for impossível). Sem tela nova; é uma migração de dado das instâncias já gravadas.
- Como verificar: rodar a automação existente cujo passo de adicionar tag falhava e confirmar que o passo aplica a tag de verdade no contato, com linha real na tabela de tags do contato, e o passo seguinte segue.
- Aceite (H1): Dado um passo de adicionar tag de uma automação criada antes do conserto do modelo, Quando a automação roda para um contato, Então a tag é aplicada de verdade no banco, E o passo fica concluído em vez de falhar por identificador de tag ausente.
- Prioridade: média. RFs: RNF-005 (dados de teste não convivem com produção). Mesma família do {AUD-25} (indicadores do Resumo) e do {AUD-33} (contagens de Usuários e Contatos). Descoberto em 2026-07-18, no planejamento do {AUD-33}, por leitura do corpo das funções do banco no serviço em produção.
- Sintoma: nas abas SaaS e Atividade do painel da agência, a tabela de maior uso por organização, o gráfico de crescimento e a distribuição por plano incluem as empresas de teste junto com a única empresa real. Como hoje cinco das seis organizações são de teste, os três gráficos mostram um retrato dominado por dado de teste, não pela operação real.
- Causa provável: as três funções do banco que alimentam esses gráficos conferem corretamente que quem chama é o Super Admin, mas nenhuma filtra a marca de empresa de teste, diferente do que o {AUD-25} fez nos indicadores do Resumo (lá o filtro foi aplicado na tela, por consulta direta que já exclui a marca de teste) e do que o {AUD-33} passou a fazer nas contagens de Usuários e Contatos (por função agregada que exclui a marca de teste).
- Contagem:
- Universo: 5. As funções do banco com definidor de segurança da família do painel da agência (prefixo agency), lidas por inteiro no serviço em produção.
- Critério: comportamental. A função alimenta um gráfico ou indicador visível do painel da agência E não restringe o resultado às empresas reais (marca de teste falsa).
- Placar: 3 alimentam gráfico visível e não filtram a marca de teste (maior uso por organização, crescimento e distribuição por plano) / 1 não filtra mas é código morto, sem nenhum ponto de chamada no frontend nem no webhook (o resumo de estatísticas, cujos campos o Resumo obtém por consulta direta filtrada desde o {AUD-25}) / 1 não filtra mas recebe a lista de organizações por parâmetro, então quem chama já escolhe o alcance e ela nunca decide sozinha (a de última fatura paga por organização). 3 mais 1 mais 1 é igual a 5. Só os 3 primeiros são o defeito vivo deste card.
- Lado negativo, lido por inteiro: as duas funções fora do placar não poluem a tela. O resumo de estatísticas não é chamado por ninguém (verificado por varredura no frontend e no webhook, zero ocorrências), e a de última fatura paga recebe a lista de organizações de quem a chama, que é a tabela de maior uso já escopada, portanto não introduz empresa de teste por conta própria.
- Universo de dados: 6 organizações, 5 de teste e 1 real (a piloto). Diferente do {AUD-39}, que é latente por não haver dado exposto hoje, este é VISÍVEL agora: os gráficos já exibem o dado de teste misturado ao real.
- Evidência de: 2026-07-18, no código em produção, medido pela leitura do corpo das cinco funções (presença do gate de Super Admin e ausência do filtro de marca de teste) e pela varredura dos pontos de chamada no frontend.
- Reprova por: RNF-005, que exige que a produção não exiba dado de teste ao operador. Os três gráficos exibem.
- O que fazer: adicionar o filtro de empresa real (marca de teste falsa) nas três funções que alimentam os gráficos, por junção com a tabela de organizações ou condição equivalente, sem afrouxar o gate de Super Admin e sem tocar as regras de isolamento. Seguir o mesmo recorte de "empresa real" que o {AUD-25} e o {AUD-33} já usam. Decidir de passagem, com registro, se o resumo de estatísticas (código morto) deve ser removido ou apenas alinhado ao mesmo filtro, para não deixar uma função que mente esperando o primeiro chamador.
- Como verificar: nas abas SaaS e Atividade, a tabela de maior uso, o gráfico de crescimento e a distribuição por plano refletem apenas as empresas reais (hoje só a piloto), e o retrato deixa de ser dominado por empresa de teste; um membro comum continua sem acesso ao painel da agência.
- Aceite (H1): Dado o Super Admin nas abas SaaS e Atividade do painel da agência, Quando abre a tabela de maior uso, o gráfico de crescimento e a distribuição por plano, Então todos contam apenas as empresas reais, E nenhuma empresa de teste aparece nos gráficos.
- Prioridade: baixa. RFs: RF-PERM-001. Descoberto em 2026-07-18, no qa do {AUD-38}.
- Sintoma: na tela de Pagamentos, o botão do cabeçalho respeita a permissão de criar, mas o botão de criar do estado vazio aparece para quem tem a permissão negada e abre o modal (o banco recusa o envio onde há reforço, então é inconsistência de tela, não furo de dados). O atalho de adicionar contato do cabeçalho aparenta o mesmo padrão e entra na varredura.
- Causa provável: os estados vazios e atalhos foram escritos sem passar pelo mesmo gating de permissão dos botões principais.
- O que fazer: varrer os estados vazios com ação e os atalhos do cabeçalho e aplicar o mesmo gating de permissão dos botões principais das telas.
- Como verificar: com papel que nega criar num módulo, nenhum botão de criar daquele módulo aparece, nem no estado vazio nem em atalho, e nada abre modal de criação.
- Aceite (H1): Dado um membro cujo papel nega criar num módulo, Quando abre a tela daquele módulo sem dados, Então nenhum botão de criar aparece, E nenhum atalho abre o modal de criação daquele módulo.
- Prioridade: alta (segurança). RFs: RF-PERM-001 (família {AUD-29}/{AUD-32}). Descoberto em 2026-07-18, no planejamento do {AUD-37}.
- Sintoma: a regra de inserção da tabela de membros de empresa tinha um segundo ramo que se pretendia "permitir o primeiro membro quando a empresa ainda não tem nenhum", mas foi escrito comparando uma coluna consigo mesma, o que é sempre verdadeiro.
- Causa-raiz, sem maquiagem: colisão de nome na origem (a subconsulta usava a mesma tabela sem apelido, então a referência que deveria apontar para a linha sendo inserida apontou para a própria subconsulta e virou uma comparação da coluna com ela mesma). O ramo deixou de significar "empresa vazia" e passou a significar "existe alguma linha de membro visível para quem insere", e essa visibilidade obedece à regra de leitura de membros. Um usuário sem nenhum vínculo de empresa enxerga zero linhas, o ramo fica verdadeiro, e ele se insere como dono de qualquer empresa. Exploração viva, não apenas futura, e ligada ao {AUD-41} (usuário que perde todos os vínculos).
- O que fazer: remover o ramo, deixando a regra permitir escrita apenas para dono e administrador da própria empresa. O primeiro membro de uma empresa nova continua nascendo pelo gatilho de criação de conta, que roda com poder próprio e não depende dessa regra, e o convite entra pelo servidor com chave de serviço, que também não depende dela. A capacidade que se perde (auto-entrada do primeiro membro pela regra) nunca funcionou de forma segura nem foi usada por fluxo legítimo.
- Como verificar: dono adiciona membro na própria empresa e é aceito; um estranho tentando inserir em empresa alheia é recusado pelo banco; um usuário sem nenhum vínculo tentando se inserir numa empresa vazia é recusado pelo banco.
- Aceite (H1): Dado um usuário autenticado que não é dono nem administrador de uma empresa, Quando tenta inserir um membro nessa empresa por chamada direta ao banco com o próprio acesso, Então é recusado, inclusive quando a empresa está vazia e quando ele não pertence a nenhuma empresa, E dono e administrador da própria empresa continuam conseguindo.
- Entregue em 2026-07-18 (merge f6b3bfd, migration 098). O ramo tautológico foi removido; a regra final permite escrita só a dono e administrador. Provado por requisição real com acesso de membro: o vetor de escalada (usuário sem vínculo tentando se inserir nas duas empresas vazias reais) passou a ser recusado, dono continua inserindo, e o nascimento do primeiro membro por gatilho e por convite seguem intactos porque não passam por essa regra.
- Prioridade: média. RFs: RF-PERM-001. Família {AUD-37}/{AUD-38}. Descoberto em 2026-07-18, no qa do {AUD-36}, bug real reproduzido.
- Sintoma: o Super Admin em modo entrar como empresa, numa subconta onde não é membro (caso típico da operação dando suporte a uma subconta), recebe recusa do banco ao criar, editar ou excluir papel pela tela de Papéis e Permissões. Bug secundário de interface na mesma reprodução: a tela não trata a recusa, o botão Criar papel fica preso em Salvando para sempre e nenhuma mensagem de erro aparece.
- Causa provável: as regras de escrita da tabela de papéis (criar, editar, excluir, da migration 096) liberam dono e administrador com vínculo na empresa e não têm o ramo que reconhece o Super Admin, diferente do padrão de outras tabelas de administração (a regra de editar empresa, por exemplo, tem esse ramo). O Super Admin sem linha de membro na empresa alvo não passa por nenhum ramo e é recusado. Na interface, a função que envia o formulário não captura a falha de gravação, então a promessa de sucesso nunca é resolvida nem rejeitada e o botão fica no estado de carregando.
- O que fazer: card único cobrindo os dois lados. No banco, migration nova acrescentando o ramo de Super Admin às três regras de escrita da tabela de papéis, no mesmo formato das demais tabelas de administração, com backup antes e o rito de sempre. Na tela, tratar a falha de gravação: parar o estado de carregando, manter os dados no formulário e mostrar a recusa como mensagem clara, sem expor texto técnico.
- Como verificar: o Super Admin em modo entrar como empresa, numa subconta onde não é membro, cria, edita e exclui papel pela tela e o papel é gravado; forçando uma falha de gravação qualquer, o botão sai de Salvando e a recusa aparece como mensagem na tela; dono e administrador da própria empresa seguem criando papel; quem não é membro nem Super Admin segue recusado.
- Aceite (H1): Dado o Super Admin em modo entrar como empresa numa subconta onde não é membro, Quando cria um papel pela tela, Então o papel é criado, E um erro de gravação qualquer aparece como mensagem na tela em vez de botão preso em Salvando.
- Prioridade: média. RFs: RF-PERM-001. Família {AUD-29}/{AUD-36}/{AUD-38d}. Descoberto em 2026-07-19, no planejamento do {AUD-38d}, por inventário do catálogo de políticas do banco ao vivo (nota D4).
- Sintoma: o {AUD-36} (migration 099) reforçou a leitura por papel só nas quinze tabelas operacionais; as tabelas dos módulos Configurações e Administração ficaram fora. Um membro cujo papel nega ver Configurações ou Administração ainda lê essas tabelas (campos personalizados, integrações, configurações de SMS e de WhatsApp, contas de e-mail, assinaturas de leads da Meta, chaves de API de saída, assinaturas de saída, membros da empresa) por chamada direta de API com o próprio token. A escrita já foi fechada pelo {AUD-38d}; a leitura não.
- Causa provável: o {AUD-36} escopou o reforço de leitura ao mapa operacional do {AUD-29} e do {AUD-38b} (as mesmas quinze tabelas de gestão) e não alcançou os módulos de configuração, que têm semântica de ver e editar própria. A regra restritiva de leitura por papel simplesmente nunca foi escrita para essas tabelas.
- O que fazer: gatear a leitura de cada tabela de Configurações e Administração pela ação ver do módulo dela no catálogo (settings.view, admin.view), uma a uma, com a mesma técnica do {AUD-36} (regra restritiva de leitura que consulta a função de autorização e convive com o token de serviço imune por vir do caminho de servidor). Antes de gatear cada tabela, confirmar que nenhum caminho público ou de servidor lê ela sem passar pelo serviço próprio, para não repetir o medo (refutado) do {AUD-36}. Backup antes e o mesmo rito da migration do {AUD-29}.
- Contagem:
- Universo: as quinze tabelas operacionais que o {AUD-36} (migration 099) gateou na leitura por papel, mais o balde nominal de Configurações e Administração alcançável por leitura de membro (as nove tabelas do recorte real do {AUD-38d}). As quinze operacionais são contadas pela própria migration 099; as nove de configuração, pelo catálogo de políticas do banco ao vivo em 2026-07-19, não por busca de texto no código.
- Critério (comportamental): a tabela devolve linhas num pedido de leitura por chamada direta de API com o token de um membro cujo papel nega ver aquele módulo, sem que nenhuma regra restritiva de leitura consulte a função de autorização por papel.
- Placar: leitura por papel = 15 tabelas operacionais gateadas (migration 099, {AUD-36}) + 0 tabelas de Configurações e Administração gateadas + 9 tabelas de Configurações e Administração ainda sem reforço de leitura. As 15 operacionais fecham contra a migration 099; o recorte deste card são as 9. Snapshots e aplicações de snapshot ficam fora (super-admin-only, sem leitura de membro), como no {AUD-38d}. Fecha: 15 gateadas + 9 sem reforço = 24 tabelas dos dois mapas, com as 9 do recorte todas do lado sem reforço.
- Lado negativo (lido por inteiro): integrations e custom_field_definitions, ambas com política de leitura permissiva por vínculo de empresa (org_id) e sem regra restritiva de leitura por papel no catálogo ao vivo de 2026-07-19, devolvem linhas a um membro autenticado hoje independentemente do que o papel dele nega ver.
- Amostra de um tenant? Não. Contagem estrutural do catálogo de políticas do banco, que vale para toda empresa, não de uma amostra de dados de um tenant.
- Evidência: 2026-07-19, catálogo de políticas ao vivo (gate de planejamento do {AUD-38d}, nota D4), posterior à migration 099 (merge 151fef5) e à migration 101 (merge cd5efd2), que gatearam a escrita e não a leitura de Configurações e Administração. O gap é o que a 099 deixou de fora de propósito.
- Reprova por: RF-PERM-001. H1 literal: "Então o membro passa a operar somente dentro do que foi liberado, E o banco recusa o que o papel nega". Ler um módulo cujo ver o papel nega é operar fora do que foi liberado, por leitura direta de API.
- Como verificar: par positivo e negativo com membro de papel que nega ver Configurações e Administração na empresa de teste, por tabela: a leitura negada devolve zero linhas por API direta; quem tem a permissão de ver recebe as linhas; dono, administrador e Super Admin sem mudança; os caminhos públicos e de servidor (troca de token de OAuth, sincronização, workers) seguem lendo.
- Aceite (H1): Dado um membro cujo papel nega ver Configurações ou Administração, Quando pede os dados dessas tabelas por chamada direta de API, Então recebe zero linhas, E as páginas públicas e os caminhos de servidor seguem lendo, E nenhuma consulta legítima passa a voltar vazia em silêncio.
- Prioridade: média (decidido, executável). RFs: RF-PERM-001. Família {AUD-29}/{AUD-38d}. Descoberto em 2026-07-19, no planejamento do {AUD-38d}, por leitura da função de autorização (nota D3).
- Sintoma: a função de autorização por papel (migration 089) trata o membro sem papel definido (vínculo com a empresa, mas sem papel atribuído) de forma assimétrica entre os dois módulos de configuração: para Configurações o padrão de editar é negado, para Administração o padrão de editar é liberado. Na prática, a regra restritiva de escrita por papel que o {AUD-38d} colocou nas três tabelas de Administração (chaves de API de saída, assinaturas de saída, membros da empresa) não barra um membro sem papel nem em tese, porque o padrão já o aprova; a mesma regra nas tabelas de Configurações barra.
- Causa provável: no padrão seguro da função de autorização, excluir e editar Configurações são negados explicitamente para o membro sem papel, e todo o resto é liberado por omissão; editar Administração não recebeu o mesmo tratamento explícito e cai no ramo do resto, ficando liberado. É uma decisão de produto que ficou implícita e nunca foi cravada.
- O que fazer: aplicar o fix. A migration 103 muda, na função de autorização por papel, o padrão do membro sem papel para editar Administração de liberado (por omissão) para negado explícito, espelhando o de Configurações, com backup da função antes e o rito de sempre (migration aditiva, DO block fail-closed, rollback que recria a função bit a bit, qa com token de membro sem papel, review). O RF-PERM-001 já foi endurecido na mesma decisão para nomear o padrão seguro por módulo (o padrão do membro sem papel nega editar tanto Configurações quanto Administração; excluir segue negado), então a assimetria passa a ter requisito que a reprova.
- Decisão (2026-07-22, Wladimir): negar o padrão de editar Administração para o membro sem papel, em simetria com Configurações. O par previsto (RF endurecido mais fix) fica absorvido neste card: o RF-PERM-001 já foi endurecido e este card passa a ser o fix da migration 103, sem card novo.
- Contagem:
- Universo: as três tabelas do módulo Administração gateadas pelo {AUD-38d} (chaves de API de saída, assinaturas de saída, membros da empresa). Contado pelo mapa do {AUD-38d} (recorte admin de três tabelas), conferido na função de autorização do banco ao vivo.
- Critério (comportamental): com o papel do membro sem definição, a função de autorização retorna liberado para editar Administração, então a regra restritiva de escrita por papel não barra esse membro nessas tabelas nem em tese.
- Placar: 3 tabelas de Administração = 3 com padrão de editar liberado para o membro sem papel (assimetria) + 0 com padrão que barre. Fecha: 3 + 0 = 3. Contraste medido: nas tabelas de Configurações o padrão de editar do membro sem papel é negado, então lá a mesma regra barra.
- Lado negativo (lido por inteiro): chaves de API de saída e assinaturas de saída, ambas com o padrão de editar liberado por omissão para o membro sem papel na função de autorização ao vivo, não barram esse membro pela regra de papel; hoje inertes por outro motivo (as regras permissivas dessas duas são só de dono e administrador, e o membro sem papel já não passa por elas), então a assimetria não abre furo vivo agora.
- Amostra de um tenant? Não, e além disso o universo de membros sem papel em produção é zero hoje (todos os seis membros são donos), então a assimetria é latente por dois motivos. Contagem estrutural da função de autorização, que vale para toda empresa.
- Evidência: função de autorização por papel (migration 089) no banco, gate de planejamento do {AUD-38d}, nota D3, 2026-07-19.
- Reprova por: RF-PERM-001, endurecido em 2026-07-22 para nomear o padrão seguro do membro sem papel por módulo (nega editar tanto Configurações quanto Administração; excluir negado). O requisito é violado quando um membro sem papel atribuído edita Administração, fato verificável por chamada direta de API contra o banco. Antes desta decisão nenhum RF reprovava a assimetria, porque o requisito governava só o que o papel libera ou nega, não o padrão do membro sem papel.
- Como verificar: um membro sem papel definido é recusado pelo banco ao tentar editar uma tabela de Administração por API direta, do mesmo modo que já é recusado em Configurações; dono, administrador e Super Admin sem mudança; um papel que libera editar Administração continua conseguindo.
- Aceite (H1): Dado um membro sem papel definido, Quando tenta editar uma tabela de Administração por chamada direta de API, Então o banco recusa, do mesmo modo que já recusa em Configurações, E um papel que libera editar Administração continua conseguindo (par positivo e negativo), E dono, administrador e Super Admin seguem editando Administração sem mudança.
- Prioridade: alta (logo após o {AUD-41}, de que é irmã: o {AUD-41} fechou a porta do banco, este fecha a porta da tela e do sistema de login). RFs: RF-AGY-017 (ingresso sem auto-atendimento, endurecido nesta mesma decisão), RF-AGY-001 (subcontas só pelo Super Admin), RNF-010 (perímetro autenticado). Recomendado pelo planejamento de 2026-07-22, com a medição já feita.
- Sintoma: o produto é um painel interno em que a operação da Modulareasy provisiona as subcontas, mas existe uma página pública de criar conta, viva, ligada na página de apresentação e na tela de entrada (o link "Criar conta"), e o sistema de autenticação está com o auto-cadastro habilitado e a confirmação automática ligada. Qualquer pessoa na internet cria uma conta. Antes do {AUD-41} isso disparava o provisionamento automático de empresa (a origem das órfãs daquele card); depois do {AUD-41} a conta nasce só com perfil, sem empresa e sem vínculo, cai num painel vazio, e vira conta-lixo acumulável e superfície de abuso (criação de contas em massa). Medido em 2026-07-22: o cadastro público criou um perfil de fato, sem empresa (validação do {AUD-41}, Teste 1).
- O que fazer: fechar a porta da tela e do sistema de login, sem tirar o convite. Remover ou desativar a página pública de criar conta e os dois pontos que levam a ela (o link na página de apresentação e o "Criar conta" da tela de entrada), e desligar o auto-cadastro no sistema de autenticação, deixando a trava de auto-registro ligada. O convite por servidor com token de serviço não passa por essa trava: é o caminho administrativo de convite, autenticado por token de serviço, que ignora a trava de auto-cadastro (confirmado na documentação do sistema de autenticação, cujo convite é um endpoint administrativo separado do cadastro público, e provado neste ambiente no Teste 2 da validação do {AUD-41}, que criou o membro convidado com o token de serviço). Assim a operação continua provisionando subconta pelo assistente do Super Admin e convidando membro normalmente. Limpeza de código no mesmo card: a função de banco generate_slug, que montava o identificador amigável da empresa dentro do provisionamento automático que o {AUD-41} removeu, ficou órfã (nenhuma função do banco e nenhum código do aplicativo a chamam, conferido em 2026-07-22, e o review do {AUD-41} já a marcou como candidata a remoção); confirmar zero chamadores no instante do conserto e removê-la.
- Como verificar: um visitante sem convite não encontra caminho de auto-cadastro (a página pública de criar conta não existe mais, e nem a página de apresentação nem a tela de entrada oferecem "Criar conta"), e uma tentativa direta contra o sistema de autenticação, com o auto-cadastro desligado, é recusada; o convite de membro por token de serviço continua criando o usuário e o vínculo (repetir o Teste 2 do {AUD-41} com o auto-cadastro já desligado, para provar que a trava não bloqueia o convite); o assistente de criação de subconta do Super Admin segue provisionando empresa; e a função generate_slug não existe mais no banco, sem quebrar nenhum caminho.
- Aceite (H1): Dado o auto-cadastro desligado e a página pública de criar conta removida, Quando um visitante sem convite tenta criar uma conta por qualquer caminho da tela ou direto no sistema de autenticação, Então nenhuma conta nasce, E o convite de membro por token de serviço e o assistente do Super Admin seguem criando usuário e subconta, E a função generate_slug foi removida do banco sem quebrar caminho nenhum.
- Entregue em 2026-07-22 (GoTrue signup off + frontend sem /signup + migration 104, merge b121c7d); convite via token de serviço provado com auto-cadastro desligado.
- Prioridade: baixa (pré-existente, sem impacto vivo hoje, e não é regressão do {AUD-41}). RFs: RF-AGY-001 (o assistente provisiona a subconta e anexa o dono). Descoberto em 2026-07-22, no qa do {AUD-41} (Teste 3), achado separado registrado no próprio gate.
- Sintoma: no assistente de criação de subconta do Super Admin, a criação da organização funciona, mas o passo seguinte, anexar alguém como dono, falha com recusa do banco (violação de regra de linha) quando o e-mail escolhido já tem perfil no sistema e o Super Admin ainda não é membro daquela organização recém-criada. O caminho comum, e-mail novo que ainda não tem perfil, não passa por esse anexo na hora da criação e por isso não sente o problema; o buraco só aparece no recorte "dono já cadastrado".
- Causa provável: a regra permissiva de inserir na tabela de membros exige que quem insere já tenha papel de dono ou administrador naquela organização, e a função que resolve o papel do usuário na organização olha só a tabela de membros, sem o desvio de Super Admin que outras regras de administração têm. A regra restritiva paralela (a que tem o desvio de Super Admin) só é satisfeita se a permissiva também passar, e a permissiva não passa para um Super Admin que ainda não é membro daquela organização. As duas regras vêm das migrations 098 (2026-07-18) e 101 (2026-07-19), ambas anteriores à migration 103 do {AUD-41}, portanto o gap é pré-existente e não foi introduzido por aquele conserto.
- O que fazer: dar à função que resolve o papel do usuário na organização o desvio de Super Admin (reconhecer o Super Admin sem exigir linha de membro), ou tornar a regra restritiva de inserir membro também permissiva, para que o desvio de Super Admin que ela já carrega passe a valer sozinho. Migration nova, aditiva, com backup antes e o mesmo rito das migrations de permissão do {AUD-29}, mais o par de teste positivo e negativo.
- Como verificar: pelo assistente, o Super Admin cria uma subconta e anexa como dono um e-mail que já tem perfil, e o vínculo é gravado; o caminho de e-mail novo continua funcionando; dono e administrador de uma organização seguem inserindo membro nela; quem não é membro nem Super Admin segue recusado ao inserir membro numa organização onde não tem papel.
- Aceite (H1): Dado o Super Admin criando uma subconta pelo assistente, Quando anexa como dono um e-mail que já tem perfil, Então o vínculo de dono é gravado sem recusa do banco, E quem não é membro nem Super Admin continua recusado ao inserir membro numa organização onde não tem papel.
ENTREGUE em 2026-07-23 (merge 297ae20): o aviso fixo do rodapé foi removido. Quem tem integração conectada não vê mais aviso de pendência, e nenhum texto manda a empresa cliente mexer em servidor. Conferido com os olhos, em tema claro e escuro.
RF-INT-001 e RF-INT-005. Achado no smoke visual real de 2026-07-23, durante a sub-fatia 2 do {C-MCRM-2}.
O problema: no rodapé da tela de Integrações existe um aviso amarelo permanente dizendo que, para conectar Meta, Google e TikTok, é preciso configurar as credenciais no servidor. Ele aparece sempre, para qualquer empresa, inclusive para a que já está conectada, e não depende de nada estar realmente pendente. Além de fixo, ficou falso: as credenciais da Meta já estão configuradas e passaram a ser editáveis pela operação numa tela própria, não no servidor. Para a empresa cliente o texto é pior ainda, porque manda fazer no servidor uma coisa que ela não faz e não deveria fazer.
O que fazer: remover o aviso fixo e, se houver mesmo pendência, dizer a verdade no lugar certo, no card da integração que está pendente, com o motivo real daquela integração e para quem cabe resolver. Corrigir a causa, nunca deixar um aviso explicando limitação.
Como verificar: uma empresa com a Meta conectada não vê aviso de pendência nenhum; uma integração de fato não configurada mostra a pendência no próprio card dela, com motivo verdadeiro; nenhum texto manda a empresa cliente mexer em servidor.
Aceite (H1): Dada a tela de Integrações, Quando a empresa tem uma integração conectada, Então nenhum aviso de pendência aparece sobre ela, E quando uma integração está de fato pendente o motivo aparece no card dela e é verdadeiro, E nenhum texto instrui a empresa cliente a configurar credenciais no servidor.
Onda C-MCRM, Conexão Meta permanente e captura confiável de leads (2026-07-22)
Origem: council de arquitetura de 2026-07-22 (GO condicional), a partir do requisito do dono de conexão Meta permanente e de que o CRM não pode perder lead. Esta onda reflete a revisão dos RFs de captura P1 (RF-CAPT-001, RF-CAPT-008 a RF-CAPT-010) e de integração Meta (RF-INT-001, RF-INT-005, RF-INT-006) no DRS. É a raiz da correção do {AUD-42} (conexão Meta morta) e absorve o padrão do {AUD-99} (caixa de saída) para o enriquecimento de leads. O construto novo é greenfield: a conexão Meta atual já está morta, então nada em produção se perde ao construir o mecanismo novo. Prioridade relativa à fila vigente. A fila do MDS segue na ordem do documento: o próximo card continua sendo o {AUD-41}, depois o {AUD-42}. Esta onda é pilar P1 core (captura de leads Meta), então tem precedência de produto sobre o backlog de auditoria de prioridade média e sobre a Fase 6; a sequência exata entre o {AUD-41} e o início desta onda fica para o Wladimir cravar na próxima sessão do MCRM. O gate externo (verificação de negócio e revisão de acesso avançado da Meta) tem calendário próprio e não é controlado pelo produto, por isso o {C-MCRM-1} pode começar em paralelo desde já sem bloquear o restante da fila. Ordem interna da onda: {C-MCRM-1} destrava tudo; {C-MCRM-3} independe de {C-MCRM-2}; {C-MCRM-4} depende de {C-MCRM-2} e {C-MCRM-3}; {C-MCRM-5} converge no destino de {C-MCRM-4}; {C-MCRM-6} fecha o {AUD-42} junto com {C-MCRM-2}; {C-MCRM-7} entra por último.
RF-INT-001 e o item 7 de 9.1 do DRS. Pendência de infraestrutura, passo humano, NÃO é card de código.
O que fazer: criar na conta de negócio do fornecedor um aplicativo Meta dedicado à captura de leads do ModularCRM, separado do aplicativo do módulo social de outro produto; configurar o identificador de configuração do Login do Facebook para Empresas; solicitar acesso avançado das permissões de leadgen (recuperação de leads, gestão de anúncios de páginas, gestão de negócio, engajamento de páginas); guardar identificador do aplicativo, segredo e config_id como configuração por produto, editável pela operação, nunca fixo no código; concluir a rotação pendente do segredo do aplicativo (registrada no {AUD-42}).
Gate externo: verificação de negócio do fornecedor e aprovação da revisão da Meta, com calendário próprio da Meta, fora do controle do produto.
Progresso (2026-07-22, sessão assistida com o dono, ATUALIZADO na mesma noite): o primeiro aplicativo criado (identificador 1038609848548875, fluxo novo de casos de uso) saiu com tipo Nenhum e NÃO oferece o Login do Facebook para Empresas; virou órfão a remover (aguarda aprovação do dono). O aplicativo definitivo FOI CRIADO pelo fluxo clássico com tipo Empresa: nome ModularCRM Lead Capture, identificador 2158863151561776, vinculado ao portfólio empresarial do fornecedor (aprovação automática). Produto Login do Facebook para Empresas instalado com a configuração MCRM Lead Capture Permanente, config_id 1038137908590530, token de usuário do sistema com expiração NUNCA, ativos Páginas e Contas de anúncios, 5 permissões (leads_retrieval, pages_manage_ads, pages_read_engagement, pages_show_list, business_management). URI de redirecionamento do OAuth cadastrado. A verificação de negócio do fornecedor JÁ EXISTIA (verificada desde 2021): o gate externo encolheu para a revisão da Meta. Solicitações de acesso avançado INICIADAS para leads_retrieval e pages_show_list; as demais destravam na verificação de acesso, e a submissão final da análise exige o produto demonstrável, o que NÃO bloqueia o início da construção (modo de desenvolvimento funciona com o portfólio do fornecedor). Restam: submissão final da análise da Meta quando o fluxo existir, segredo do aplicativo lido de configuração por produto, rotação pendente do segredo do aplicativo antigo do {AUD-42}, e a remoção do aplicativo órfão.
Como verificar: o aplicativo dedicado existe e está separado do aplicativo do social; o config_id abre o fluxo de Login do Facebook para Empresas; identificador, segredo e config_id são lidos de configuração, não do código.
Aceite (H1): Dado o aplicativo Meta dedicado criado e configurado, Quando uma empresa inicia a conexão, Então o fluxo usa o aplicativo dedicado ao lead capture e não o do social, E os segredos vêm da configuração por produto editável pela operação.
RF-INT-001. Depende de {C-MCRM-1}. É a raiz da correção do {AUD-42}.
O que fazer: implementar o fluxo de conexão por empresa que grava, no caminho primário, o acesso de usuário de sistema do negócio do cliente (não expira no caminho feliz, preso ao negócio e não à pessoa); para a empresa sem verificação de negócio, o caminho alternativo (acesso de longa duração com renovação) marcado na tela como menos permanente; armazenar o acesso e os metadados por empresa, cifrado em repouso, com isolamento por empresa.
Como verificar (teste primeiro): uma empresa conecta uma vez pelo caminho primário e o registro guarda um acesso de usuário de sistema sem vencimento no caminho feliz; a conexão é visível só para aquela empresa; a empresa sem verificação cai no caminho alternativo e a tela sinaliza menos permanente; religar deixa de ser exigência de operação normal.
Aceite (H1): Dado o fluxo de Login do Facebook para Empresas, Quando uma empresa autoriza uma vez pelo caminho primário, Então fica gravado um acesso de usuário de sistema do negócio do cliente que não expira no caminho feliz, isolado por empresa, E a empresa sem verificação de negócio usa o caminho alternativo sinalizado como menos permanente.
Progresso (2026-07-22): a primeira sub-fatia fechou. A configuração do aplicativo Meta (identificador e config_id) deixou de morar fixa no código e passou a viver numa tela própria do Super Admin, editável sem depender de nova versão do sistema (migration 105, com o identificador 2158863151561776 e o config_id já semeados); o segredo do aplicativo, por ora, ainda é lido pelo caminho antigo como transição, com a gravação cifrada nova pronta mas ainda vazia. O webhook Meta já lê a configuração nova. qa PASS e review APPROVED, merge e3a523e em main. Progresso (2026-07-23): a segunda sub-fatia fechou. O caminho primário de conexão passou a ser o Login do Facebook para Empresas: a tela de Integrações, ao pedir para conectar a Meta, agora manda a empresa para o fluxo do aplicativo dedicado usando a configuração permanente, sem listar permissão por permissão. Ao voltar, o sistema pergunta à Meta que tipo de acesso recebeu antes de guardar: acesso de usuário de sistema é gravado como permanente, sem data de vencimento; acesso comum continua sendo estendido para longa duração e guardado com vencimento. Se a Meta não responder essa pergunta, o acesso NUNCA é gravado como permanente por adivinhação, e fica registrado que a decisão veio do caminho de recuo. Provado em produção com clique real na tela: a conexão sai com a configuração permanente do aplicativo novo e sem lista de permissões. As sub-fatias 3 e 4 fecharam em 2026-07-23 (merge 297ae20, migration 106). A renovação do caminho alternativo passou a ser decidida por VENCIMENTO, e não pela presença de um campo que a Meta nunca preenche, defeito que fazia o renovador nunca rodar para a Meta desde sempre; o prazo de aviso virou parâmetro editável em vez de número fixo no código. Nasceu a sonda de saúde da conexão, que roda de hora em hora e distingue três verdades: viva, morta e não sei. Falha de rede ou instabilidade da Meta NUNCA marca uma conexão viva como morta, o que evitaria mostrar "expirada" para um cliente saudável e desligar a captura de leads dele. A tela passou a mostrar o estado honesto: permanente sem contador de validade, longa duração com o prazo, e expirada com o motivo em português mais o botão de reconectar. Nasceu também o painel de saúde para a operação. Provado em produção: a sonda respondeu que as duas conexões estão vivas, sem nenhum segredo aparecendo em tela.
O card {C-MCRM-2} segue em aberto de propósito: o mecanismo inteiro está construído, mas ninguém ainda se conectou pelo caminho primário. Falta gravar o segredo do aplicativo novo e uma pessoa autorizar na Meta, os dois do {C-MCRM-1}. Enquanto o segredo não é gravado, o sistema opera coerente no aplicativo antigo e vira para o novo de uma vez só quando ele chegar.
Defeito encontrado e corrigido na mesma sessão, que teria quebrado a conexão: a configuração estava sendo montada campo a campo e misturava a identificação do aplicativo NOVO com o segredo do aplicativo ANTIGO. A Meta recusava esse par, então a autorização teria falhado no retorno, depois de a pessoa já ter autorizado. A escolha da fonte passou a ser atômica: ou tudo da configuração, ou tudo do ambiente, nunca metade de cada. O que ainda não pôde ser provado ponta a ponta é a autorização em si, que exige uma pessoa autorizando na Meta, e a gravação do segredo do aplicativo novo, ambas do {C-MCRM-1}. Ressalva de segurança (achado do review, 2026-07-22, RESOLVIDA em 2026-07-23 na sub-fatia 2): a validação de assinatura do webhook Meta lia o segredo antigo direto da variável de ambiente e falhava aberta, ou seja, deixava passar, se essa variável sumisse. Agora ela lê a configuração cifrada, nega quando não há segredo nenhum, e aceita durante a migração tanto o segredo do aplicativo novo quanto o legado da variável antiga, para que gravar o segredo novo não derrube de uma vez os webhooks das conexões que ainda assinam pelo aplicativo antigo. A guarda também ganhou a garantia de nunca derrubar o processo: qualquer falha ao ler a configuração vira recusa, não queda do serviço inteiro.
RF-CAPT-008. Independe de {C-MCRM-2}: a ingestão não usa o acesso da empresa.
O que fazer: endpoint de leadgen que valida a assinatura pelo segredo do aplicativo, grava o evento cru (leadgen_id, formulário, página, momento) numa tabela de entrada idempotente por leadgen_id, e responde sucesso em poucos segundos.
Como verificar (teste primeiro): notificação com assinatura válida grava uma linha e responde sucesso rápido; assinatura ausente ou inválida é recusada sem gravar; a mesma notificação duas vezes gera uma única linha; com o acesso da empresa vencido, o evento ainda é gravado.
Aceite (H1): Dado o endpoint de leadgen, Quando chega uma notificação assinada válida, Então o evento é gravado por leadgen_id e a resposta é de sucesso em poucos segundos, E assinatura inválida é recusada sem gravar, E duas notificações do mesmo leadgen_id geram uma única linha, E o evento é gravado mesmo com o acesso da empresa vencido.
RF-CAPT-009. Reusa o padrão da caixa de saída do {AUD-99}. Depende de {C-MCRM-3} (lê a entrada) e usa o acesso de {C-MCRM-2}.
O que fazer: processo que lê a tabela de entrada, busca o conteúdo do lead na Meta com o acesso da empresa, grava o contato de forma idempotente por leadgen_id, com recuo progressivo; quando o acesso está morto, a linha fica em aguardando reconexão e nunca é descartada; ao reconectar, drena o acumulado. Intervalo e recuo editáveis pela operação.
Como verificar (teste primeiro): com acesso vivo, um evento vira contato uma única vez e a linha fica concluída; com acesso morto, a linha fica em aguardando reconexão sem sumir; ao reconectar, o acumulado é enriquecido; dois eventos do mesmo leadgen_id não viram dois contatos.
Aceite (H1): Dado um evento de leadgen na entrada, Quando o enriquecimento roda com acesso vivo, Então o contato é gravado por leadgen_id uma única vez e a linha fica concluída, E com acesso morto a linha fica retida sem descarte, E ao reconectar dentro da janela da Meta o acumulado é drenado sem perder evento.
RF-CAPT-010. Não diferível (o caminho só de webhook tem perda silenciosa). Converge no mesmo destino de {C-MCRM-4}.
O que fazer: em intervalo configurável (inicial 15 minutos), buscar os leads de cada formulário desde o último cursor e convergir por leadgen_id para o mesmo destino do webhook, deduplicando.
Como verificar (teste primeiro): um lead entregue só pela reconciliação (o webhook não entregou) vira contato; um lead já capturado pelo webhook não vira segundo contato; o cursor por formulário avança e não reprocessa tudo.
Aceite (H1): Dado um formulário ativo, Quando a reconciliação roda no intervalo configurado, Então os leads desde o último cursor convergem por leadgen_id para o mesmo destino do webhook, E um lead já capturado não vira segundo contato, E um lead que o webhook não entregou passa a existir.
RF-INT-006 e RF-INT-005. Fecha o {AUD-42} junto com {C-MCRM-2} (faz "conectada" significar conectada).
O que fazer: job que monitora por empresa validade e vencimento do acesso, permissões concedidas, assinatura de formulário e página, relação de negócio ativa; alerta proativo na Central de Notificações, por empresa, com a marca da agência, acionável, nunca por WhatsApp; quando o acesso morre, a ingestão continua, o enriquecimento e a reconciliação pausam preservando o cursor, nada é descartado; a tela de conexões deixa de dizer "conectada" sobre acesso morto e oferece reconectar. Limiares editáveis pela operação (prazo do alerta, janela considerada).
Como verificar (teste primeiro): um acesso invalidado gera aviso acionável na Central com a marca da agência e não por WhatsApp; a tela para de dizer "conectada"; com acesso morto a ingestão segue e o enriquecimento fica retido; ao reconectar, drena.
Aceite (H1): Dado uma conexão Meta que fica inválida, perde permissão crítica ou se aproxima do vencimento no caminho alternativo, Quando o monitor roda, Então a empresa recebe na Central um aviso acionável com a marca da agência para reconectar, E o status deixa de dizer "conectada", E nenhum aviso desse tipo vai por WhatsApp, E a ingestão de leads continua enquanto o enriquecimento fica retido.
RNF-008 e a seção 6 do council. Depende de os valores existirem ({C-MCRM-1} a {C-MCRM-6}).
O que fazer: expor no painel do Super Admin os valores editáveis: intervalo do poll de reconciliação (inicial 15 minutos), política de recuo do enriquecimento (inicial 1 minuto a 6 horas), prazo do alerta proativo de token (inicial 7 dias), janela de retenção considerada (aproximadamente 90 dias, leitura, limite da Meta), identificador do aplicativo, segredo e config_id por produto, e as permissões solicitadas por produto. A chave de idempotência (leadgen_id) e a verificação de assinatura são protocolo da Meta, não editáveis.
Como verificar (teste primeiro): cada valor acima é alterável pela tela sem mexer no banco nem reimplantar; os identificadores e segredos do aplicativo por produto são lidos da configuração, não do código.
Aceite (H1): Dado o painel do Super Admin, Quando a operação altera o intervalo de reconciliação, o recuo, o prazo do alerta ou os segredos do aplicativo por produto, Então o novo valor passa a valer sem mexer no banco nem reimplantar, E os valores de protocolo da Meta não são editáveis.
Definição de Pronto da Onda C-MCRM. Uma empresa conecta a Meta uma vez e recebe leads sem religar de rotina; um lead nunca se perde (webhook assinado independe do acesso, reconciliação cobre o que o webhook não entregou, enriquecimento fica retido até reconectar dentro da janela da Meta); acesso morto vira alerta acionável na Central com a marca da agência, e "conectada" nunca aparece sobre acesso morto; os valores de operação são editáveis pelo painel. Isso fecha o {AUD-42} e absorve o {AUD-99} para a captura de leads. A migração das conexões sociais de outro produto é ciclo separado e não faz parte desta onda.
- Prioridade: baixa. RFs: RF-CONV-014. Descoberto no planejamento do {AUD-45} (2026-07-24).
- Sintoma: o ajuste shortlink_base_url aparece editável na tela de configurações da agência, mas a URL do shortlink é montada com um valor fixo no código do front (trigger-links-tab.tsx), então mudar o ajuste não muda nada. Mesma classe do {AUD-45}, arguivelmente pior porque afeta a base da URL inteira.
- O que fazer: ou o front passa a ler shortlink_base_url, ou o ajuste sai do painel (admin-editable-first: o que está no painel tem que valer).
- Como verificar: mudar shortlink_base_url no painel e exibir um link novo usa a base configurada.
- Aceite (H1): Dado que o administrador altera shortlink_base_url, Quando um shortlink é exibido, Então a URL usa a base configurada.
- Prioridade: baixa. Descoberto no planejamento do {AUD-45} (2026-07-24).
- Sintoma: a tela de configurações da agência renderiza toda linha da tabela settings genericamente, então qualquer chave órfã (setting que nenhum código lê) vira um input editável que promete um controle inexistente. Foi assim que o {AUD-45} e o {AUD-110} nasceram.
- O que fazer: auditar as chaves de settings por critério (toda chave, algum código a lê?) e restringir a tela a uma lista de chaves que de fato produzem efeito, catalogando as chaves mortas encontradas.
- Como verificar: a tela de configurações só mostra ajustes que produzem efeito; nenhuma chave morta editável.
- Aceite (H1): Dado a tela de configurações da agência, Quando um ajuste é listado, Então alterá-lo produz efeito observável no produto.
- Prioridade: alta (bloqueava salvar a configuração do app Meta). Descoberto ao vivo em 2026-07-24 ao gravar o secret do app Meta dedicado em /admin/meta-app.
- Sintoma: getAuthHeaders() fazia await supabase.auth.getSession() como único ponto antes de todo fetch autenticado do canal /api. O getSession pode nunca resolver (deadlock do LockManager / navigator.locks do supabase-js): a mutation nunca settla e o botão fica preso em "Salvando..." para sempre, sem nenhum request chegar ao servidor. A tela fingia estar salvando.
- Fix: o getSession passou a correr contra um timeout de 3s; no estouro ou erro, cai para a leitura direta do token no storage do supabase-js (sem lock). O caminho feliz é idêntico; só adiciona resiliência. Entregue 2026-07-24 (commit 79a7fe4, merge na main), deploy de frontend (bundle auth-headers-9R2nszpE.js). Provado end-to-end: o save da tela completa, o PATCH chega ao webhook (dois writes registrados), o banco grava (updated_at avança) e o botão não trava mais. gates plan GO, qa PASS, review APPROVED.
- Aceite (H1): Dado o save de uma tela do canal /api com o getSession em deadlock, Quando o usuário salva, Então a operação completa ou erra em no máximo 3s, nunca prendendo o botão indefinidamente.
- IRMÃO do {AUD-104}, mesma classe (lock do supabase-js) e SUPERFÍCIE DIFERENTE: o {AUD-104} (tela de Papéis e Permissões) salva por supabase.from().insert() (canal PostgREST), que NÃO passa pelo getAuthHeaders; segue aberto e pede o fix definitivo no createClient. O council de 2026-07-24 vetou o desenho ingênuo: NÃO é a opção auth.lock (já existe na lib 2.101.1 e não cobre o vetor re-entrante). O vetor real é o fetch da auth SEM timeout segurando o lock; o fix é dar timeout ao fetch da auth via AbortController (fetch NATIVO, nunca o impersonateFetch, pra não vazar x-impersonate-org no refresh) com lockAcquireTimeout (15s) MAIOR que o fetch (10s) pra não deslogar entre abas. Exige repro empírico provando que o hang é auth (rede para ANTES do insert) e não dado/RLS, e smoke de 2 abas sem logout, ANTES do merge.