ADR-0081 — Tiers de conformidade por estágio de produto
15/08/2026 · aceita
docs/adr/ADR-0081-tiers-de-conformidade-por-estagio.md
ADR-0081 — Tiers de conformidade por estágio de produto
Status: aceita Data: 2026-08-15 Decisor(es): Marcelo Lermen (board) + Claude Code controller
Contexto
O board pediu revisão das boas práticas, padrões e quality gates, propondo uma lista de ~12 artefatos obrigatórios para todas as aplicações (PRD, UML, RBAC, multi-tenancy, RLS, secret management, catálogo de funcionalidades, botão de report de erro, testes, security audit, WAF/Bot Fight/rate-limiting, TLS full strict).
O pré-voo mediu o que já existe e o que a casa consegue sustentar. Três achados mudam a forma da decisão.
Achado 1 — metade da lista já existe, e o que existe é bom
| item | onde | estado |
|---|---|---|
| Testes (unit/integração/E2E) | dev-standards §9 — ~150 linhas | maduro |
| RLS | §10 + 12 ADRs + padrão #3 (FK no WITH CHECK) | maduro |
| Secret management | §10 + gitleaks (pre-commit + CI) + Keychain | existe |
| Multi-tenancy | §10 "tenant isolation testado a cada release" | existe |
| RBAC | 3 ADRs + 2 runbooks | existe, disperso |
| Rate limiting | §10 + 4 ADRs | decidido, não aplicado |
| Rollback | 19 runbooks com seção própria | existe |
| a11y (axe) | gate bloqueante no ci.yml desde 19/06 | existe |
Faltam de verdade: PRD, mapa de arquitetura, WAF/Bot Fight, TLS full strict, botão de report de erro, catálogo de funcionalidades, prova de restore.
Achado 2 — o gargalo não é falta de padrão, é padrão que ninguém verifica
Medido em um único dia (15/08), sem procurar por isso:
| mecanismo | tempo morto em silêncio |
|---|---|
snapshot de FinOps (com.tynna.token-snapshot) | 35 dias, 37 falhas |
smoke-test-scripts | ~2 meses, 539 testes invisíveis |
DRIFT-BAN | 5 acusações crônicas, 3 falso-positivo |
Semgrep (fixture de JWT no mento) | nunca detectada — scan incremental |
teste em diretório fora do include do vitest | 2 ocorrências no mesmo dia |
Adicionar obrigação a uma casa onde as existentes falham caladas piora a razão sinal/ruído. Cada item sem verificador é mais um lugar onde alguém escreve "✅ feito" e ninguém confere.
Achado 3 — a distribuição de esforço estava invertida
O apps/jep é o único produto com cliente pagante (ARMELS, publicado nas duas lojas) e era, até 15/08, o único sem error tracking. Os dois apps que tinham Sentry — web e mento — são justamente os sem receita.
Piso único não teria pego isso: teria distribuído exigência igualmente entre 7 apps, diluindo atenção em vez de concentrá-la onde há cliente.
Opções consideradas
(a) Piso único para todos os apps. Simples de enunciar. ⛔ Trava labs pré-receita com exigência de produção (WAF num app sem usuário é custo e falso-positivo), e dilui atenção — o oposto do que o Achado 3 pede.
(b) Três tiers (lab / usuário real / cliente pagante). Granularidade fiel à realidade. ⛔ Três checklists para manter numa casa cujo problema medido é não conseguir manter o que já tem. E o degrau do meio é o menos objetivo de definir.
(c) ⭐ Dois tiers, com promoção detectada por script. Piso enxuto para todo repo; Produção para o que tem usuário externo. A promoção não depende de alguém lembrar.
(d) Nada — manter como está. ⛔ Deixa o Achado 3 sem resposta.
Decisão
Adotamos (c): dois tiers, com detecção automatizada e a regra do verificador.
Os dois tiers
| tier | quem | exige |
|---|---|---|
| Piso | todo repo/app | TS strict · lint · testes de lógica pura · .env.example · secrets fora do código · error tracking |
| Produção | app com usuário externo (alguém que não somos nós) | Piso + RLS testada + E2E happy-path + a11y (axe) + headers de segurança + rate-limit + TLS strict + LGPD + prova de restore |
A regra que sustenta tudo
Item sem comando que prove seu estado não entra como gate — vira recomendação.
Isso não é preferência de estilo: é a conclusão do Achado 2. Regra escrita não muda gesto automático; ferramenta muda. Um item que só existe como frase em documento tem, nesta casa, histórico documentado de ficar meses sem cumprimento sem ninguém notar.
Promoção de tier é detectada, não lembrada
O registro (data/standards/conformance.yaml) declara o tier de cada app, e pnpm standards:check compara a declaração com os sinais da árvore. Um app declarado piso que já exibe sinais de produção (E2E configurado, testes de RLS, headers de segurança) é reportado como promoção pendente.
⚠️ Limitação declarada: a detecção é por proxy, não prova de que há usuário externo — nenhum sinal no repo prova isso. Ela existe para atacar o modo de falha real (app cresce, ninguém promove), não para decidir sozinha. A palavra final é do registro, que é editado por humano ou agente com justificativa.
O que fica de fora, e por quê
- UML — recusado. Diagrama não gerado do código apodrece em meses, e a casa tem histórico disso. Substituído por C4 nível 1–2 em Mermaid versionado: renderiza no GitHub, entra no diff, e o revisor vê quando a arquitetura mudou sem o desenho mudar.
- "Catálogo de funcionalidades" — recusado como item novo. Se é para humano, é o PRD; se é para a frota saber o que reusar, já existe
docs/standards/reuso-catalogo.md. Criar um terceiro artefato para o mesmo fim contraria a regra de ouro do§7(uma informação tem UM dono). - WAF/Bot Fight — só no tier Produção. Em app pré-lançamento é custo e risco de falso-positivo sem benefício.
Documentação continua no repo; o Paperclip aponta
A proposta de hospedar a documentação dos projetos no Paperclip foi avaliada e recusada na forma de cópia. O projeto no Paperclip tem um campo description; doze documentos ali viram monólito ou duplicata. O CLAUDE.md §8 (regra dura, 30/07) e o dev-standards §7 já decidem: "cópia apodrece em silêncio — o dono atualiza um lado só".
O que fazemos: doc técnica no repo; o description do projeto no Paperclip vira índice com links, não conteúdo.
Correção de contradição entre canônicos
O dev-standards §7 mandava estado de projeto, OKRs, tasks e dashboards para o EuGestor, enquanto o CLAUDE.md §6 e o ADR-0027 dizem Paperclip. Dois canônicos em conflito. Este ADR corrige o §7 para refletir o ADR-0027.
Consequências
Positivas
- Atenção concentrada onde há cliente pagante, em vez de distribuída por 7 apps.
- O registro torna o estado de conformidade medível — hoje ele não era.
- Detecção de promoção ataca o modo de falha que já se repetiu 5× em um dia.
- Menos artefatos novos que a proposta original: 3 recusados com justificativa.
Negativas / riscos
- ⚠️ O registro pode apodrecer como qualquer artefato manual. Mitigação:
standards:checkcompara declaração × árvore e falha quando diverge. - ⚠️ A detecção por proxy gera falso-positivo (um lab pode ter E2E por disciplina, sem usuário externo). Por isso ela reporta, não bloqueia.
- ⚠️ Dois tiers são grosseiros para um portfólio que pode crescer. Se o degrau do meio voltar a doer, isso é motivo para um ADR novo — não para adicionar tier em silêncio.
- O tier Produção tem itens ainda não implementados (WAF, TLS strict, prova de restore, LGPD). O registro os marca como pendentes em vez de fingir conformidade.
Estado inicial medido (2026-08-15)
app tier error-tr testes e2e rls headers
jep producao sim 127 sim 32 sim
mento producao sim 76 sim 24 sim
web producao sim 33 sim 0 NAO
publisher piso NAO 20 sim 0 sim
grana piso NAO 23 - 0 NAO
chat-bridge piso NAO 4 - 0 NAO
grana-bot piso NAO 3 - 0 NAO
Relacionado
TYN-3196— gate incremental não vê o baseline (a classe do Achado 2)TYN-964/TYN-865— error tracking do JeP (#1538)TYN-3202— botão de report de erro (fatia 2)- ADR-0027 — Paperclip como source of truth de coordenação
dev-standards §7,§9,§10,§15b
Só leitura. Toda mudança nestes documentos é pull request.