ADR 0078 — Moldura de tela, e o registro de abas diverge do handoff de propósito
- Status: aceito
- Data: 2026-08-15
- Contexto anterior: RN-048
(promoção de história pendente), RN-104 (Chat e
Criativo como lugares, com a chave
sessions), RN-121 (aba Executores, dev agent e QA fora do "Time de agentes" misturado), ADR 0075 (embeddings no contrato deLLMProvider— fundação sem consumo)
Contexto
O checklist "moldura de tela" do handoff de design (design_handoff_brabo/CHECKLIST-CONFRONTO.md,
seção 2) descreve a faixa que envolve toda tela de projeto: header de 60px,
régua de abas logo abaixo, aba ativa com box-shadow: inset 0 -2px 0 var(--accent), rolagem horizontal em telas estreitas, e container de conteúdo
com largura máxima 960–1040px. O código de ProjectPage.tsx tinha os quatro
defeitos: header com padding variável em vez de altura fixa, aba ativa com
border-bottom (não box-shadow), sem rolagem horizontal declarada, e sem
teto de largura no container de conteúdo.
Corrigir os quatro é o essencial deste ADR, mas a parte que precisa de decisão
— e não só de CSS — é outra: o handoff lista 7 abas (Visão geral, Criativo,
Código, Chat RAG, Gastos, Aprovações, Configurações) e o registro
(apps/web/src/routes/project-tabs.ts) tem 10. As três a mais são
executores, backlog e insights.
O handoff é de uma leva anterior do PROGRAMA 16–26. Entre a leva que o desenhou e hoje, três coisas aconteceram que ele não podia prever:
- Executores nasceu na FASE 27 (RN-121) quando o grid de agentes saiu da Visão geral para uma aba própria — dado real (status ao vivo, modelo vinculado, toggle de autonomia), não maquete.
- Backlog tem contador próprio de histórias aguardando promoção do usuário desde a Fase 12c (RN-048) — outra fila de decisão, com regra de negócio e teste cobrindo o quê e quando ela soa.
- Insights mostra as hipóteses do Psicólogo esperando aceitar/descartar — a terceira fila de decisão do projeto, existente desde antes do handoff ser escrito.
Nenhuma das três é redundante com as 7 do handoff, e nenhuma é ornamento: todas têm dado real, contador derivado de consulta, e pelo menos uma RN própria com teste. Apagá-las para "bater" com o handoff destruiria informação que o produto já sabia mostrar.
Decisão
As 10 abas ficam. O handoff é referência de fidelidade VISUAL — cores, tipografia, espaçamento, o desenho da moldura — não teto de quantas abas o produto pode ter (RN-203). Ele fixa como cada tela deve SE PARECER; não congela o inventário de funcionalidades no dia em que foi escrito. A regra já valia implicitamente (a FASE 26 registrou a aba Código sem o handoff prever "Executores" nem "Insights" como abas separadas, e ninguém cogitou removê-las por isso) — este ADR só a torna explícita, com teste que reprova se alguém "arrumar" o registro contra o handoff sem ler esta decisão.
A chave sessions continua rotulada "Chat", nunca "Chat RAG" (RN-202). O
handoff chama essa aba de "Chat RAG" nas telas mais recentes
(designs/Brabo Chat.dc.html), e a tentação óbvia seria só trocar a string do
rótulo. A rejeição é literal: "Chat RAG" descreve uma FUNCIONALIDADE — consulta
por embeddings sobre o repositório indexado, com citação de fonte — que o
produto não tem. O ADR 0075 pôs embed no contrato de LLMProvider
(capability provada só no Ollama), mas nada ainda CONSOME essa operação: não
há pipeline de indexação, não há índice vetorial por projeto, não há UI de
citação. A aba sessions de hoje é o Chat CONSULTIVO comum (RN-104) — um
agente respondendo com o contexto da sessão, igual ao Criativo, só que sem
produzir backlog. Rotulá-la "Chat RAG" hoje seria a mesma mentira que o ADR
0042 recusa para modelo de catálogo: anunciar uma capacidade antes de ela
existir, só porque o nome já está reservado no design.
As quatro correções literais da moldura, sem exceção declarada:
- Header como piso, não teto.
.headerTop(o cabeçalho de identidade do projeto — ícone do provider, nome, chip de repositório, branch/adotado — e oTokenMetercompacto) ganhoumin-height: var(--header-h)(60px), nãoheight. O conteúdo desta faixa é mais rico do que o cabeçalho genérico que o handoff desenha nas 6 telas internas (título 18/600 + subtítulo mono- chip + indicador): o card do
TokenMetersozinho, com o próprio padding interno, já soma cerca de 70px. Forçar 60px cortaria o alerta de orçamento — e a RN-088 já estabeleceu que falha/estado nunca vira invisível; cortar o orçamento por estética seria a mesma classe de erro com outro nome.min-heighthonra o token como PISO — quando o conteúdo é mais simples (semTokenMeter, por exemplo, em carregamento), a faixa fica perto de 60px; quando não é, ela cresce, visível.
- chip + indicador): o card do
- Aba ativa com
box-shadow: inset 0 -2px 0 var(--accent), nãoborder-bottom, emTabs.module.css. A diferença visual entre os dois é pequena, masborder-bottomdesloca o layout em 2px na troca de estado (a borda ocupa espaço mesmo transparente-vs-sólida quando mal implementada) e o handoff é explícito no atributo. Os valores de espaçamento (gap: 2px,padding: 11px 13px) que viviam como override de CSS de descendente emProjectPage.module.css— pendência declarada desde a FASE 16 ("quando ela puder mudar, o lugar disto é lá") — migraram para a primitiva, porque esta onda deu o mesmo dono aos dois arquivos. - Rolagem horizontal (
overflow-x: autoem.list,flex-shrink: 0ewhite-space: nowrapem.tab) — não existia; a régua quebraria linha ou espremeria rótulos em telas estreitas. - Largura máxima do container de conteúdo —
.bodyganhoumax-width: 1040px; margin: 0 auto, para as abas em forma de documento (Backlog, Aprovações, Insights, Gastos, Configurações, Criativo, Chat). Continua sem teto nas abassemRespiro(Visão geral, Código): a primeira tem um trilho lateral próprio, e a segunda é "a aba mais custosa do programa" nas palavras do próprio handoff — as duas usam a tela inteira de propósito.
O rótulo "Code" virou "Código". Nenhum outro ponto do código compara pela
STRING do rótulo (busca confirmada por grep); a CHAVE de registro e de
deep-link continua code, intocada.
Consequências
O registro de abas fica, deliberadamente, maior que a intenção original do handoff — e cada item a mais tem RN e teste próprios apontados neste ADR. Quem ler só o handoff e comparar com o código vai ver uma divergência; quem ler este ADR entende que ela é escolhida, não esquecida.
Nenhuma FORMA de export mudou. AbaDoProjeto continua com os mesmos
campos (key, label, component, count?, ordem, semRespiro?), e
ABAS_DO_PROJETO continua sendo o array ordenado que outros consumidores
(a Frente B do shell de navegação, em paralelo nesta mesma onda) leem para
listar as abas de um projeto na sidebar — só o VALOR do rótulo de code
mudou, e a lista de chaves não perdeu nem ganhou nenhuma.
"Chat RAG" fica reservado, não cancelado. Quando o pipeline de indexação e
a UI de citação existirem, a aba sessions deste registro é onde a
funcionalidade chega — o nome muda naquele dia, com o dado por trás dele.
Renomear antes seria a mesma classe de erro que o ADR 0042 já nomeou para
modelo: "ativar" a aparência de uma capacidade sem a capacidade.
Fica de fora, declarado: o dropdown rico de branch da aba Código, a UI de blame e a lista de PRs (FASE 26b) não são tocados por este ADR — moldura é sobre o CONTORNO das telas, não sobre o conteúdo interno de cada uma.