Files
DeskcommCRM/evidence
Rafael César Rocha MonteiroandClaude Opus 5 72d2ed4c35 build(tailwind): migra para o Tailwind 4 com config em CSS
O `tailwind.config.ts` deixa de existir. O que era `theme.extend` virou um
bloco `@theme inline` em `app/globals.css` — o modo `inline` é o que preserva o
tema, porque o utilitário recebe o `var(--color-…)` literal em vez de uma cópia
do valor claro. Os três blocos de token (`:root`, `[data-theme="light"]`,
`[data-theme="dark"]`) ficam exatamente onde estavam: `extrairRegua`
(lib/branding/contraste.ts) acha o bloco claro por igualdade EXATA de seletor, e
`branding-tema-claro-escopavel` compara prop a prop os blocos claro e escuro.

O que a migração destapou, e é o item de maior impacto visual:

  No v3, modificador de opacidade sobre cor declarada como `var(--…)` sem
  `<alpha-value>` fazia o Tailwind NÃO EMITIR a regra — em silêncio. Todo token
  deste produto é `var(--color-*)`, então 62 classes distintas em 252 usos eram
  letra morta: `bg-destructive/10` não pintava fundo nenhum, `border-destructive/30`
  caía na cor neutra da regra global de borda, `text-muted-foreground/60` herdava
  a cor do pai. O v4 resolve opacidade por `color-mix()` e as 252 passaram a
  pintar. Medido contra um `tailwindcss@3.4.19` de descarte: alimentado com 7
  classes, ele emitiu 4 — nenhuma das 3 com barra.

Renomes mecânicos (58 `rounded` puro → `rounded-md`, 22 `outline-none` →
`outline-hidden`, 4 `flex-shrink-0` → `shrink-0`). O `rounded` puro não podia
ficar: o v3 remapeava o DEFAULT para `--radius-md` (8px) e o v4 tem um `rounded`
embutido de 0.25rem que nem `@utility` sobrescreve — o raio encolheria pela
metade em 33 arquivos, sem erro nenhum.

Guardas novas em `tests/unit/tailwind-tokens.test.ts`, porque a migração troca um
arquivo que o TypeScript conferia por um que ninguém confere: reprova config em
JS de volta, `:root` embrulhado em `@layer` (que ligaria a auto-referência que o
`@theme inline` emite), token referenciado que não existe, pasta de UI fora do
`@source`, e a volta dos três utilitários renomeados.

`branding-rampa` fatiava o CSS com `indexOf('[data-theme="dark"]')` e quebrou:
o `@custom-variant` pôs essa string no topo do arquivo. Passa a recortar o
`:root` por casamento de chaves.

Provado na tela, em instalação fresca (baseline.sql + bootstrap-owner + Supabase
local), medindo por `getComputedStyle` e nunca a olho — onboarding completo em
claro e escuro, 0 erro de console. Sonda em `tests/sonda-tailwind-4.ts`,
capturas e medições em `evidence/tailwind-4/`.

NÃO verificado: o build da imagem Docker. Os binários musl de `@tailwindcss/oxide`
e `lightningcss` estão no lockfile para linux x64 e arm64, mas docker.io está
inalcançável nesta máquina — quem prova é o `imagens-ok` no PR.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 01:48:00 -03:00
..
…
…
…
…
…
…

evidence/ — as provas visuais do CRM Vivo

Cada wave tem seu índice: wave-0.md, wave-1.md, wave-2.md. Os PNGs são a prova; os .md dizem o que cada um prova, contra qual commit, e o que ficou vermelho.

Os dois tipos de evidência — e por que a distinção não é burocracia

REPRODUZÍVEL HISTÓRICA
Como regenerar rodar o script de novo não dá
Por quê o código que a produz continua lá o código que produziu aquele estado não existe mais
Sobrescrever inofensivo destrói a única cópia, sem deixar rastro do que havia
Exemplo wave-2-board-depois.png wave-0-board-antes.png

O "antes" de uma wave vira histórico no instante em que a wave é commitada. A partir dali, aquele PNG é a única testemunha de um estado que ninguém consegue mais reconstruir — nem com git checkout, porque o board depende de dados, de build e de um servidor vivo naquele momento.

Tratar evidência histórica como saída de script é erro de categoria: script produz artefato descartável; registro histórico é imutável por natureza.

A proteção

tests/qa-helpers.ts mantém a lista EVIDENCIA_HISTORICA. Antes de gravar, o guardaEvidencia() recusa sobrescrever um desses arquivos — e diz qual arquivo e por quê:

[evidencia] RECUSADO sobrescrever "wave-0-board-antes.png": é evidência HISTÓRICA — o
código que produziu aquele estado não existe mais, então este PNG é a única cópia e não
pode ser regenerado.
Se você realmente quer perder o "antes", rode com FORCE=1.

Recusar em silêncio seria a mesma falha silenciosa que esta entrega inteira existe para caçar. A recusa grita, nomeia o arquivo e oferece a saída consciente (FORCE=1).

Evidência reproduzível segue sobrescrevendo sem atrito — a guarda só vale para a lista.

Como uma evidência nasce

Todo PNG aqui veio de navegação como usuário: login pela tela (com MFA quando o papel exige), cliques até o destino, zero navegação por URL direta e zero asserção de API tratada como prova. Os capturadores:

Script O que produz
tests/capture-wave-0.ts linha de base do board (histórica)
tests/capture-wave-1.ts os 4 cenários do dono-agente + axe + paridade de avatar
tests/capture-wave-1-bulk.ts atribuição em massa sobre lead de dono agente
tests/capture-wave-2.ts gate de altura constante, orçamento de elementos, axe
tests/compose-antes-depois.ts o antes/depois lado a lado (cenário 8)

tests/capture-wave-2.ts tem dois modos que auditam o próprio instrumento:

  • DEMO=1 — imprime a mensagem de falha sem navegador, para revisar o formato do relatório antes de precisar dele;
  • SELFCHECK=1 — infla um card por CSS e exige que o gate reprove. Gate que só foi visto passando é carimbo, não gate.