Files
DeskcommCRM/docs/prd
Rafael Melgaço c7e5308af7 fix(295): a doutrina acompanha o detector novo, e o conserto do modelo sobrevive ao refetch
Consertos de triagem sobre o #295. Os cinco consertos dele ficam — medi um a um e
os cinco são reais (a conta fecha: cinco afirmados, cinco entregues).

── 1. DoD 16: quatro documentos descreviam um detector que deixou de existir ───

`git diff --name-only origin/main...pr/295 -- docs/ CLAUDE.md '*.md'` era VAZIO, e
depois do merge estas quatro afirmações ficariam falsas em documento de
autoridade — o modo de falha nº 1 da triagem, e o motivo de o DoD 16 existir
(a auditoria de 2026-08-14 achou 227 afirmações desatualizadas em 393):

  CLAUDE.md:92 · docs/business-rules/…:172 (W-02, hard constraint) ·
  docs/prd/03-…:231 · docs/research/reference-synthesis.md:121

Todas trocadas seguindo a receita do próprio CLAUDE.md — "onde a afirmação puder
virar comando, troque em vez de corrigir". Em vez de recopiar uma regex nova que
envelhece igual, elas passam a apontar para `lib/opt-out/deteccao.ts` e para as
frases de controle do teste, com o comando que as lê.

── 2. Uma DECISÃO REGISTRADA estava sendo revertida em silêncio ───────────────

`ADR-EPIC03-07` diz literalmente: "STOP detection é match exato regex (palavra
isolada). **Frases livres NÃO bloqueiam**". O #295 inverte isso — "não quero mais
receber", "me tira da lista" e "cancelar inscrição" passam a bloquear.

A reversão é a coisa CERTA (a regra antiga deixava passar 21 de 33 pedidos reais,
e opt-out é direito legal num produto vendido como LGPD-nativa), mas o CLAUDE.md
exige abrir item de revisão, não sobrescrever. A ADR-07 fica marcada como
supersedida, com o porquê, e entra a **ADR-EPIC03-07b**.

E há uma ironia que vale registrar: a ADR-07 existia para evitar falso positivo,
e a implementação nunca foi "match exato" — a regex caçava a palavra em qualquer
posição. Ela produzia exatamente o falso positivo que a decisão queria evitar. A
decisão escrita e o código nunca coincidiram.

── 3. O conserto nº 4 ("modelo em vigor") não sobrevivia ao primeiro refetch ───

O PR acrescentou o join `versao_publicada` ao Server Component, mas a lista é
re-hidratada por `useAgentsList` → `GET /api/v1/ai/agents`, cujo `AGENT_COLUMNS`
não tinha o join. O cartão voltava a mostrar o id do CADASTRO na primeira
revalidação. Duas fontes para a mesma lista têm de pedir as mesmas colunas.

O join entra numa constante SEPARADA, usada só na listagem: pedi-lo no POST faz o
tipo da linha recém-inserida deixar de resolver (`GenericStringError` —
reproduzido, `tsc` acusou nas linhas 158 e 170), e é coerente, porque agente
recém-criado tem `published_version_id = null` por construção.

── 4. A religação do runtime não era vigiada por NENHUM dos 5123 testes ───────

Medido: revertendo só `lib/agent-engine/agent/human-handoff.ts` para a versão
antiga — que reintroduz as duas regras divergentes cuja unificação é o conserto
nº 1 — a suíte inteira fica VERDE (458 arquivos, 5123 casos, exit 0). O PR
protegeu o outro lado (`pos-entrada.ts` tem assertiva de import), e este ficou
descoberto.

Dois casos de COMPORTAMENTO, não de texto — as frases só respondem certo pela
regra nova. Sabotado: revertendo o arquivo, 1 de 46 falha; restaurado, 46/46.

── 5. Dois consertos menores ──────────────────────────────────────────────────

- O dublê do SELECT em `arquivar-agente-arquiva-mesmo` tinha aridade FIXA de dois
  `.eq()`. Um filtro novo o quebraria com "maybeSingle is not a function", erro
  que não fala do comportamento vigiado. É a armadilha que mordeu três vezes
  nesta rodada; virou encadeável sem limite, como o dublê do UPDATE ao lado.
- `app/app/ai/agents/page.tsx` descartava o `error` do SELECT — e o join novo
  acrescentou uma causa de erro a ele. "Não consegui perguntar" e "você não tem
  agente nenhum" pintavam a MESMA tela, e a segunda é uma afirmação forte sobre o
  trabalho de quem instalou. Continua degradando para lista vazia (a tela não
  pode quebrar), mas agora deixa rastro.

── Verificação ───────────────────────────────────────────────────────────────

`tsc --noEmit` exit 0 · `pnpm lint:channels` ok · 88 casos verdes nas seis suítes
tocadas pelo PR.

NÃO MEDIDO: nada pela tela. Os itens de UI foram verificados por código, teste e
sonda de componente — não por navegador em ambiente fresco (DoD 12).
2026-08-21 07:13:01 -03:00
..