Files
DeskcommCRM/lib/email
Rafael MelgaçoandClaude Opus 5 4aa65590e0 feat(orcamento): a tela deixa de mentir, e a IA que para avisa gente
Ondas 4 e 5, que fecham o conserto: o controle da tela passa a valer, o sistema
paralelo morto sai, e um bloqueio deixa de abandonar o lead.

`DESKCOMM_GOV_INVARIANTS_EDIT=1` — dois invariantes MODIFICADOS, e a razão:
`vocabulario-banco-x-typescript` ganhou o par `ModoDeOrcamento` (coluna nova com
CHECK precisa de par no TypeScript, senão o job `invariants` reprova), e
`orcamento-apos-backfill` acompanhou a mudança do piso. O invariante NOVO
(`orcamento-nasce-desarmado`) não precisa da flag.

## Os três achados que valeram mais que a feature

**1. A escolta era inalcançável no caso dominante.** `classifyStage` roda em
todo turno e estourava ANTES da escolta — que, portanto, nunca protegia o
caminho normal. Movida para `runAgentTurn`, que envolve o turno inteiro. A
guarda antiga contava `runModelCall(` no texto e era cega para helpers; agora
conta call sites e a fronteira dos auxiliares.

**2. A escada era contornável pela REST do Supabase** (migration 0160). O PATCH
exige `off → avisar → bloquear`, mas `ai_budgets` aceitava escrita direta de
`authenticated` — qualquer cliente com a anon key pulava a escada e armava
bloqueio imediato. `revoke insert/update/delete`, SELECT fica.

**3. O texto mandava clicar num botão que não existe.** A mensagem que o cliente
lê quando a IA para dizia "Retomar atendimento automático"; o componente
renderiza **"Devolver ao automático"**. Corrigido em 7 arquivos, e a guarda nova
**lê o rótulo do componente** em vez de guardar uma cópia — cópia de rótulo é a
próxima mentira esperando envelhecer.

## O dropdown decorativo saiu

"Ação ao atingir 100%" oferecia "Pausar" vs "Desabilitar" e o produto entregava
sempre a mesma coisa. Era o defeito que este trabalho existe para matar,
sobrevivendo dentro do conserto — um juiz reprovou um desenho inteiro por
mantê-lo. Ou entrega os dois futuros, ou sai. Saiu.

## O lead não fica mais no vácuo

Quando o orçamento barra, o turno vai para `performHumanHandoff` com contexto, e
o job é **cancelado** (`cancelJob`), não falhado com retry: repetir uma chamada
que o teto recusa é gastar de novo para receber a mesma recusa. O caminho legado
ganhou o mesmo veto — e depois dos gates que reconhecem "quero falar com um
atendente", não antes, senão pedir humano viraria silêncio.

## Sabotagem: 10 previsões, 10 acertos

escolta fora do turno 3×3 · piso só para bloquear 3×3 · não zerar a carência 2×2
· veto antes dos gates 1×1 · sem handoff 1×1 · ressalva de medição sumida 1×1 ·
rótulo do período revertido 2×2 · flag de gasto incompleto fixa 1×1 · janela do
mês removida 1×1 · botão renomeado 3×3.

## Uma discordância mantida, com evidência

O KPI de plataforma fica na coluna acumulada. A alternativa barata seria um
`group by` inline — a segunda régua de gasto que `orcamento-uma-regua-de-gasto`
existe para impedir, e o gate provou o ponto reprovando o próprio comentário do
implementador quando ele escreveu a query em PROSA. Mitigado: nunca `critical`,
rótulo "acumulado", divergência escrita no arquivo e link para a tela que tem a
régua certa.

## Bateria

typecheck 0 · lint 0 erros · lint:channels 0 · test:shell 0 · build 0 ·
test:unit **3347 passam**, 1 falha — a baseline do `.env.local` deste worktree,
que não cita orçamento, budget, handoff nem money.

## NÃO MEDIDO, declarado

- `tests/invariants/orcamento-nasce-desarmado.test.ts` é **novo e nunca foi
  executado** (15 casos, e é a primeira vez que `SQL_ORCAMENTO` roda contra
  Postgres em todo o repo). É o maior risco de CI vermelho desta entrega, e está
  escrito aqui porque dívida declarada não é defeito — dívida presumida é.
- O `revoke` da 0160 não foi provado contra PostgREST vivo: o achado veio de
  leitura de grants.
- **DoD 12 (prova pela tela): NÃO MEDIDO.** Radio, kill switch e badge estão
  provados por unidade em jsdom e por `build`, não por browser em ambiente fresco
  estilo VPS.
- `test:db`, `e2e` e `build-and-size`: quem prova é o CI.

Nota de release em `docs/release/teto-de-orcamento.md`; mapa vivo em
`docs/architecture/teto-de-orcamento.architecture.json` (26 nós, 43 arestas).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCiffR3ugjQbxsfceQE2GB
2026-08-15 10:58:07 -03:00
..