0008 — A caixa azul do passo Documentos afirma o que o sistema não faz¶
| Status | CORRIGIDO |
| Branch | fix/0008-caixa-azul-do-passo-documentos |
| Aberto em | 2026-08-14 |
| Severidade | MÉDIA |
| Apps afetados | api (sem impacto) · web · e2e |
| Nota do diagnóstico | 8,7 (tentativa 1 de 3) |
| Nota da correção | 8,3 (tentativa 2 de 3) |
Status:
RASCUNHO→DIAGNOSTICADO→EM CORREÇÃO→CORRIGIDO
O fix atravessa dois portões, cada um com nota de 0 a 10 dada por um subagente verificador de contexto limpo, em até 3 tentativas, passando a partir de 7,0:
- O diagnóstico (seções 1 a 4) é validado na seção 5 (reprodução × causa raiz). É o portão barato: sem ele, o segundo mede o conserto contra um palpite.
- A correção (o diff e os testes) é validada na seção 11 (correção × regressão), com duas perguntas — atacou a causa ou o sintoma, e o que prova que não volta.
1. Sintoma¶
No passo Documentos da análise de crédito, a primeira coisa da tela é uma caixa azul com o título "Registro criado" e o texto:
A análise
P202608-00006já existe e aceita anexos. Cada documento é gravado contra ela.
O relato foi de que o texto "não está claro". Ao abrir o código, o problema é maior que clareza — são três defeitos empilhados na mesma caixa, e o terceiro é o grave:
- "gravado contra ela" é jargão traduzido. É o inglês recorded against; em português "gravado contra" soa adversativo, como se o documento pesasse contra a análise. Este é o que o relato pegou.
- "Registro criado" aparece sem nada ter sido criado. No screenshot o cabeçalho diz "Editar análise de crédito" e o selo diz "Em edição" — a análise
P202608-00006foi criada às 07:58 e está sendo reaberta depois. A caixa anuncia a criação de um registro que já existia. - "Cada documento é gravado contra ela" é falso. Documento de inquilino, de corresponsável e de imóvel é gravado no cadastro da entidade, não na análise. Só a área Adicionais da análise grava na análise.
O terceiro é conferível no próprio screenshot, sem abrir o código: quatro linhas abaixo da caixa, na linha do CPF, o app escreve "Já no cadastro de José da Silva · 12/08/2026". A tela afirma as duas coisas ao mesmo tempo — que todo documento é gravado na análise, e que aquele documento mora no cadastro da pessoa.
O efeito prático não é estético. A caixa é a única explicação que a tela dá sobre onde o arquivo vai parar, e ela ensina o modelo errado: quem lê conclui que anexar ali é um ato local à análise, e portanto que remover o documento afeta só esta análise. Não afeta — remove do cadastro da pessoa, para todas.
2. Reprodução¶
- Entrar como usuário da garantidora com
credit_analyses:update. - Abrir uma análise que já existe em
DRAFT— no dev-remote,P202608-00006. - Editar, e ir ao passo 2 · Documentos.
- Ler a caixa azul no topo, e depois a linha do CPF, logo abaixo.
Observado: a caixa diz "Registro criado — a análise P202608-00006 já existe e aceita anexos. Cada documento é gravado contra ela", enquanto a linha do CPF diz "Já no cadastro de José da Silva · 12/08/2026".
- Ambiente: dev-remote (
https://dev.garantora.com.br/app), garantidora "Garantidora". A análise do relato existe no banco:P202608-00006,DRAFT,created_at = updated_at = 2026-08-14 07:58:54— nunca editada depois da criação, e ainda assim reaberta em modo de edição no horário do screenshot. - Superfície: ambos. A caixa é um
<Alert>sem variação por breakpoint (DocumentsStep.tsx:132-139). O relato veio do mobile — o print anexado ao pedido é de um iPhone (barra de status às 07:24, aba inferior "Análise de Crédito" visível), e é ali que a caixa pesa mais, por ocupar o topo de uma tela de 812px. A verificação visual doimplementdeve começar por esse viewport. Não é agravado pelo PWA — é texto literal no bundle, não dado cacheado. - Dados/pré-condições: basta a matriz do tenant exigir algum documento numa área de pessoa ou imóvel, que é o caso normal. Com exigência só em Adicionais, a frase seria verdadeira e o defeito 3 não apareceria.
3. Esperado × Atual¶
- Esperado: a caixa explica onde o arquivo vai parar e não contradiz a linha logo abaixo; e não anuncia criação quando nada foi criado.
- Atual: anuncia criação incondicionalmente, e afirma que todo documento é gravado na análise — o oposto do que o código faz nas três áreas de pessoa e na do imóvel.
4. Causa raiz¶
Onde¶
apps/web/src/pages/credit-analyses/components/DocumentsStep.tsx:132-139— o<Alert>é renderizado sem condição nenhuma, com título e frase literais. Não há ramo para "acabei de criar" × "estou editando", nem para a área do bloco.apps/web/src/pages/credit-analyses/components/DocumentsStep.tsx:45-53—blockEntity()é o código que decide o destino do anexo, e o comentário dele diz, com todas as letras: "A entidade que recebe o anexo — deriva do bloco, não da análise".renter_id→renter;property_id→property; só o resto →credit_analysis. A caixa afirma exatamente o contrário do que está documentado nove linhas acima dela.apps/web/src/pages/credit-analyses/CreditAnalysisForm.tsx:429—if (a.status === "PENDING") setStep(2). Uma análise devolvida abre direto no passo 2, e vê "Registro criado" sem ter passado por criação nenhuma nesta sessão.
Não é regressão, e a origem explica o texto. O git log -S"gravado contra ela" aponta uma única entrada: 6455b20 feat(web,e2e): telas de análise de crédito no design system (spec 0015). A frase nasceu junto com a tela, quando a distinção entre "documento da análise" e "documento da pessoa" ainda não existia — ela só passou a existir com a spec 0008 e a conferência por pessoa (RN8). O texto envelheceu; ninguém o releu.
O mecanismo¶
A caixa foi escrita para responder a uma dúvida real e específica do passo 2: "eu ainda não terminei o cadastro, posso anexar?". A resposta correta é sim, porque a análise já foi gravada ao sair do passo 1 (CreditAnalysisForm.tsx:547) — e é isso que "já existe e aceita anexos" diz bem.
O defeito veio de continuar a frase. Para justificar o "aceita anexos", o texto acrescentou onde o anexo é gravado — e escolheu a análise, que é o assunto da tela, sem consultar blockEntity, que é quem decide. A informação certa (a análise já foi salva, pode anexar) ficou grudada numa informação errada (e tudo fica gravado nela), e as duas chegam ao usuário como uma coisa só.
Os outros dois defeitos vêm da mesma origem: a frase foi escrita para um momento — o instante seguinte a criar a análise — e depois o componente passou a ser exibido em outros três (edição de rascunho, retorno de pendência, reabertura). Como o <Alert> não tem condição, o texto de um momento passou a narrar todos.
Por isso o bug aparece aqui e não em toda parte: é o único ponto do app que descreve por escrito o destino de um anexo. O DocumentsPanel das outras telas anexa sem explicar, e por isso não tem como se contradizer.
O alcance¶
- A caixa é uma só (
DocumentsStep), e só o passo 2 do formulário a mostra. Greppei"aceita anexos","Registro criado"e"gravado contra"noapps/web/src: as três ocorrências estão nas mesmas duas linhas. Não há cópia da frase em outro componente. - Mas a mesma afirmação errada aparece uma segunda vez, no docstring do componente (
DocumentsStep.tsx:23): "Passo 2 da inclusão: anexar, já contra o código do registro criado (spec 0015, RN9)". Não é texto de usuário, e por isso não entra no sintoma — mas é a mesma causa, da mesma origem (0015), e o mais revelador é que o parágrafo seguinte do próprio docstring (:31-34) diz o certo: "Cada documento vai para a entidade que o possui, não para a análise… só a áreaADDITIONALgrava contra a análise". O arquivo se contradiz internamente há uma spec inteira, e o conserto tem de alcançar os dois pontos — senão fica um comentário ensinando o modelo errado a quem mexer nisso depois. - Os três momentos que a caixa narra são quatro entradas no mesmo componente, e as três chamadas que levam ao passo 2 estão todas em
CreditAnalysisForm.tsx::547(criação, ao salvar o passo 1 e avançar),:562(mesma coisa numa análise já existente) e:324(análise devolvida emPENDING, que abre direto no passo 2 pela RN3 da spec 0036). A quarta é a reabertura manual de um rascunho, que cai no:562. Só a primeira justifica "Registro criado" — e é isso que a condição da correção precisa distinguir, em vez de tratar só oPENDING. - Quem lê inclui o
AGENCY_USER. A imobiliária temcredit_analyses:createeupdate(rbac_seed.py:227-229) e é ela quem mais anexa documento — é o público que mais depende de a caixa dizer a verdade sobre onde o arquivo fica, e o que tem menos contexto para desconfiar. - O fix 0007 tornou a contradição visível. Antes, a linha do documento dizia só "Anexado em DD/MM/AAAA", que não conflitava com nada. Agora ela diz "Já no cadastro de X", e as duas frases aparecem juntas na mesma tela. O 0007 não causou este defeito — ele estava lá desde a 0015 —, mas tirou dele o disfarce.
AREA_LABELSjá dá o vocabulário certo (DocumentsStep.tsx:37-42): "Inquilino (pessoa física)", "Imóvel", "Adicionais da análise". O cabeçalho de cada bloco já nomeia a entidade dona; é a caixa do topo que destoa.
5. Validação do diagnóstico¶
Preenchido pelo laço de validação do /fix new (subagente fix-diagnosis-validator). Registrar todas as tentativas, inclusive as reprovadas.
| Tentativa | Reprodução | Causa raiz | Final | Veredicto |
|---|---|---|---|---|
| 1 | 8,7 | 9,0 | 8,7 | APROVADO |
Resultado: aprovado na tentativa 1 com nota 8,7 (mínimo: 7,0).
Pendências aceitas: —
Aprovado de primeira, e mesmo assim a lista rendeu: o validador achou que a mesma afirmação errada está no docstring do componente (
:23), contradizendo outro parágrafo do próprio docstring (:31-34). Os greps da seção 4 não pegaram porque a redação lá é outra. Também pediu as trêsarquivo:linhaque levam ao passo 2, em vez de só a doPENDING— é o que permite ao portão da correção conferir se a condição nova cobre todos os caminhos. As duas coisas foram incorporadas antes de fechar.
6. Correção¶
Preencher com /fix implement.
apps/api¶
- Sem impacto. Nenhum endpoint, schema ou regra muda: o destino do anexo já está correto no código; o que mente é a frase que o descreve.
apps/web¶
- Onde:
components/DocumentsStep.tsx— a caixa (:132-139) e o docstring (:23), que carrega a mesma afirmação errada. - O quê: a caixa passa a ser instrução, não anúncio (seção 10). Deriva do checklist que o componente já recebe: quantos obrigatórios faltam, e quantos itens vêm com
predates_analysis— os dois dados já estão em mãos, então não há chamada nova. O docstring:23é corrigido junto, para parar de ensinar o modelo errado. data-testid:credit-analysis-documents-step-hintna caixa — ela não tinha, e é o que sustenta as duas asserções novas do e2e.- Um módulo próprio,
mensagemDoPasso.ts. A decisão de qual frase mostrar é ramificada (herdado × falta × completo) e oDocumentsStepjá tem 250 linhas de renderização; deixá-la inline esconderia a regra dentro do JSX, que é como a frase anterior sobreviveu a uma spec inteira sem ninguém reler. - A prop
codesaiu. O único uso dela era a frase "a análise P… já existe"; o número segue visível no topo da tela, fora deste componente. Removida também do chamador (CreditAnalysisForm.tsx:1358) — não é carona: é o resto do que foi apagado. - Responsividade & PWA: a caixa ocupa o topo do mobile; qualquer texto novo precisa ser conferido em 375px.
apps/e2e¶
- Teste de regressão: dois casos novos em
procedencia-documento.spec.ts— o estado herdado (que é o do relato, e o único em que a contradição fica visível na mesma tela) e o estado sem herança. O segundo existe para o primeiro valer: sem ele, "Recuperamos…" passaria mesmo se a caixa dissesse isso sempre — que é exatamente o defeito de origem, um texto único narrando todos os momentos.
7. Risco / impacto colateral¶
Não toca dinheiro, regra de negócio, permissão nem dado. O risco é o inverso do usual: trocar uma frase errada por outra frase errada. A tentação é dizer "cada documento é gravado no cadastro da pessoa", que é falso para a área Adicionais da análise — o espelho exato do defeito atual.
Há também o risco de apagar a informação útil junto com a errada: "a análise já existe e aceita anexos" responde a uma dúvida real de quem está no meio de um cadastro, e some se a caixa for simplesmente removida.
8. Critérios de aceite¶
- [x] CA1. Seguindo os passos da seção 2, a caixa não afirma mais que todo documento é gravado na análise, e não contradiz a linha "Já no cadastro de …" logo abaixo.
- [x] CA2. O texto continua respondendo à dúvida que a caixa existe para responder — que a análise já foi gravada e aceita anexos agora — em todo estado em que há o que anexar, herdado ou não. Onde não falta obrigatório, a pergunta não se coloca e a frase não aparece. O CA foi reescrito assim depois da primeira rodada do portão, que mostrou que a frase tinha sobrevivido em um estado só.
- [x] CA3. Abrindo uma análise que já existia (edição de rascunho ou retorno de pendência), a tela não anuncia criação de registro.
- [x] CA4. A área Adicionais da análise continua descrita corretamente — o que é gravado na análise segue sendo apresentado como tal.
- [x] CA5. Sem jargão traduzido: nenhuma ocorrência de "gravado contra".
- [x] CA6. Em 375px a caixa não estoura nem gera rolagem horizontal.
9. Plano¶
- [x] Reproduzir o bug — pelo screenshot do relato e pelo dado:
P202608-00006existe emDRAFTcomcreated_at = updated_at, e a caixa dizia "Registro criado". - [x] Corrigir a causa raiz —
web(a caixa, o docstring e a prop morta) e depoise2e - [x] Teste de regressão que falharia se a correção fosse revertida — as três frases do defeito estão em
not.toContainText:Registro criado,gravado contra,Cada documento. - [x]
make preflight— limpo - [x]
make test— 367 passaram, 1 falhou, a intermitente já registrada. Evidência: esta branch não toca a API (git diff main -- apps/apivazio) e o teste passou isolado 3 de 3. - [x]
make lint—tsc --noEmitdo web limpo; a API não foi tocada. - [x] Validar no browser em desktop e mobile — screenshot dos dois estados nos dois viewports, contra o dev-remote reconstruído:
overflow = 0, zero erro de console. - [x] e2e executado — 8 casos, todos verdes (31,7s), sendo 4 do fix 0008.
- [x] Regra de origem unificada com a linha do documento (
possessivoDoCadastro), e os 8 casos rodados de novo depois disso — todos verdes.
10. Decisões em aberto¶
-
[x] O que a caixa deve dizer, e se deve continuar existindo. Decidido pelo usuário em 2026-08-14: a caixa continua, e deixa de anunciar criação para dizer o que fazer. São dois estados:
- Sem documento herdado — a caixa diz que agora é hora de anexar os documentos obrigatórios.
- Com documento herdado — a caixa informa que alguns documentos já foram recuperados do cadastro do inquilino, e pede que sejam validados.
A decisão resolve os três defeitos de uma vez, e não por acaso: ao trocar "o que aconteceu" (registro criado, documento gravado em X) por "o que fazer agora", os dois pontos em que a caixa mentia deixam de ser afirmados. E o segundo estado transforma o achado do fix 0007 em instrução — o documento herdado não é só identificado, é entregue com uma tarefa: conferir.
Duas extensões que a decisão não menciona e que a implementação assume, pelo texto e não pela adivinhação — registradas aqui para serem contestadas se estiverem erradas:
- A recuperação não é só do inquilino. As mesmas áreas herdam do imóvel e do corresponsável (seção 4). Dizer "do inquilino" quando o documento veio do cadastro do imóvel repetiria o defeito 3 numa escala menor. A caixa nomeia a origem pelo vocabulário que a própria tela já usa nos cabeçalhos de bloco (
AREA_LABELS), ou fala em "cadastros" quando houver mais de uma origem. - Quando tudo já está satisfeito, não há obrigatório a pedir — a caixa fica só com o pedido de conferência. É o estado do screenshot do relato, aliás: o topo da tela já dizia "Todos os documentos obrigatórios estão anexados".
11. Validação da correção¶
| Tentativa | Correção | Regressão | Final | Veredicto |
|---|---|---|---|---|
| 1 | 8,0 | 8,0 | 8,0 | APROVADO (com [REGISTRO INCOMPLETO]) |
| 2 | 8,7 | 8,3 | 8,3 | APROVADO |
Resultado: aprovado na tentativa 2 com nota 8,3 (mínimo: 7,0).
A tentativa 1 aprovou com uma marca
[REGISTRO INCOMPLETO]procedente: a frase útil da caixa antiga tinha sobrevivido em um dos três estados — exatamente o risco que a seção 7 deste registro havia previsto e que eu não conferi antes de chamar o portão. Também faltava prova do ramoPROPERTY, que a seção 10 declarava ter desenhado.Depois da tentativa 2 (aprovada), a lista ainda rendeu uma correção que valia a pena: a caixa dizia "do cadastro de imóvel" enquanto a linha logo abaixo dizia "no cadastro do imóvel". Eram duas implementações da mesma decisão em arquivos vizinhos — que é literalmente como este bug nasceu. Passaram a compartilhar
possessivoDoCadastro, e a enumeração de origens múltiplas ganhou vírgula.
Defeitos aceitos:
- O ramo "Documentos obrigatórios completos" não tem teste. É o terceiro estado, e o único sem prova executada. Vale registrar que ele é o estado do screenshot do relato — mas ali havia documento herdado, então o que a tela mostrava era o ramo herdado, que está coberto. O risco é de regressão futura.
- A contagem de obrigatórios aparece em três lugares da mesma tela (cabeçalho do formulário, esta caixa e o alerta de pendências). Nenhuma mente; unificá-las é mudança de layout que este fix não pediu.
12. Registro¶
O que era: uma caixa fixa dizendo "Registro criado — a análise P… já existe e aceita anexos. Cada documento é gravado contra ela."
O que virou: mensagemDoPasso(checklist), que deriva a caixa do estado e devolve três mensagens — confira o que foi recuperado, anexe o que falta, ou está completo. A frase útil da caixa antiga sobrevive junto do pedido de anexo.
O que divergiu do plano:
- A correção ficou mais simples que o diagnóstico previa. A causa raiz apontava para uma condição que distinguisse "acabei de criar" de "estou editando", e listou as três
arquivo:linhaque levam ao passo 2. Ao trocar anúncio por instrução, o ramo de criação deixou de existir — e os quatro caminhos de entrada ficam certos por construção, sem condição nenhuma sobre eles. - Caí no risco que a seção 7 tinha registrado. Ela avisava que apagar a frase errada podia levar junto a informação útil; a primeira rodada do portão mostrou que foi exatamente o que aconteceu — "a análise já foi gravada e aceita anexos agora" ficou em um dos três estados. A frase agora acompanha o pedido de anexo, e não um estado fixo: onde se pede anexo, a dúvida existe.
- A prova da origem "imóvel" não existia, embora a seção 10 a declarasse. O portão apontou que
origemDoBlocotinha um ramoproperty_idque teste nenhum percorria — o cuidado estava escrito e não estava provado. Entrou um caso com exigência emPROPERTY, que afirma "do cadastro de imóvel" e que o nome do inquilino não aparece. - O screenshot pegou uma concordância errada. A caixa saía com "Recuperamos 1 documento … Confira se continuam válidos". O e2e afirmava só o começo da frase e passava por cima do resto; a asserção foi apertada para a frase inteira, que é o que teria pegado sozinho.
- A prop
codemorreu junto. Era usada só pela frase apagada; saiu do componente e do chamador. O número da análise segue visível no topo da tela.
Capturas: dois estados × dois viewports, contra o dev-remote reconstruído — overflow = 0 e zero erro de console nos quatro. Não versionadas (são efêmeras); o CA6 está coberto por asserção no e2e, que é a prova que fica.
Ficou de fora, de propósito: a contagem de obrigatórios agora aparece em três lugares da mesma tela (o cabeçalho do formulário, esta caixa e o alerta de pendências). Nenhuma mente, e unificá-las é mudança de layout que este fix não pediu.