Pular para conteúdo

0057 — A mensalidade da garantia: uma faixa por tipo de tomador, escolhida na aprovação

Status CONCLUÍDA
Branch spec/0057-taxa-da-mensalidade
Criada em 2026-10-12
Apps afetados api · web · e2e
Revisão do problema aprovada na rodada 1
Revisão da experiência aprovada na rodada 1
Revisão do detalhamento aprovada na rodada 1
Revisão da implementação aprovada (fases e branch)

Status: RASCUNHO → APROVADA → EM IMPLEMENTAÇÃO → CONCLUÍDA

A spec tem três partes, escritas em ordem, e quatro portões — cada um revisado por um subagente de contexto limpo, em até 3 rodadas. A máquina de revisão é do plugin superpowers; a régua é a rubrica correspondente em .claude/rubrics/. Achados vêm classificados: qualquer Critical reprova, Important em aberto reprova salvo decisão registrada do usuário, e Minor vira pendência aceita.

  1. A Parte I diz qual é o problema e como se convive com ele hoje. Revisada na seção 6 (necessidade × jornada de hoje). É o portão mais barato de todos, e o único que pergunta contra que problema isto está sendo construído.
  2. A Parte II diz como se usa o que vai existir. Revisada na seção 8 (jornada × viewports).
  3. A Parte III diz como se constrói. Revisada na seção 16 (segurança × clareza técnica) — autorização, isolamento, e se sobrou decisão para quem vai codar.
  4. A implementação é medida contra as três, na seção 17 (aderência × qualidade × testes) — uma revisão por fase, e uma da branch inteira antes de fechar.

Cada parte só se escreve depois que a anterior passou. Descrever tela sobre problema mal enquadrado, ou detalhar endpoint sobre experiência vaga, é o jeito mais caro de descobrir que era outra coisa.


Parte I — O problema

Aqui não entra solução: nem tela, nem endpoint, nem botão. Só o que dói, para quem, e o que se faz hoje. Se você já sabe qual é a tela, guarde para a Parte II.

1. Dor

A mensalidade da garantia — o que o inquilino paga todo mês pela garantia do aluguel — é decidida caso a caso no negócio, e o sistema só sabe cobrar um número para todo mundo.

A mensalidade é um percentual sobre o Pacote Locatício (aluguel + condomínio + IPTU). A política comercial da garantidora não é um percentual único: é uma faixa, e a faixa depende de quem é o tomador. Para pessoa física a garantidora trabalha entre 8% e 11%; para pessoa jurídica, entre 15% e 18% — o risco de uma empresa inquilina é outro, e o preço também. Dentro da faixa, quem decide o percentual de cada garantia é o analista, no momento em que aprova a análise de crédito, olhando o caso.

O que o sistema oferece hoje não permite exercer essa política:

  • A garantidora tem uma faixa só, sem distinção entre pessoa física e jurídica. Não há como registrar que PF vai de 8% a 11% e PJ de 15% a 18%: um intervalo único de 8% a 18% deixaria um analista aprovar uma PF a 17% ou uma PJ a 9% sem nada que o impeça.
  • O analista não escolhe o percentual ao aprovar. A faixa existe na configuração, e por trás da tela o sistema até sabe receber um percentual na aprovação, conferi-lo contra a faixa e levá-lo à garantia — mas a tela de aprovação nunca ofereceu o campo. Na aprovação ninguém informa percentual nenhum, e toda garantia sai com a taxa padrão da garantidora. Na prática, a faixa configurada não governa nada.
  • Não há um momento para rever o número antes do contrato. Entre aprovar a análise e emitir a garantia pode passar tempo — conversa com a imobiliária, ajuste de vigência —, e a mensalidade não pode ser revista nesse intervalo.
  • Quem decide não vê o efeito em reais. O percentual é o que o analista escolhe, mas o que o inquilino e a imobiliária discutem é o valor da parcela. Hoje o valor só aparece calculado com a taxa padrão, nunca com a que está sendo considerada.
  • Os nomes da configuração confundem o assunto. As configurações têm um bloco chamado "Taxas", que mistura a taxa de garantia com multa e juros por atraso, e outro chamado "Taxas — Analistas", que é a faixa da mensalidade. Quem configura não reconhece ali "a mensalidade de PF" e "a mensalidade de PJ", que é como o negócio fala.

O custo de conviver com isso:

  • Não existe taxa padrão que sirva aos dois tipos de tomador. Com uma taxa padrão única, ou a PJ é cobrada abaixo do piso comercial dela (15%), ou a PF é cobrada acima do teto dela (11%) — não há valor único que respeite as duas faixas, porque elas nem se encostam.
  • A decisão comercial do analista não tem onde existir. Se o caso pede 9,5%, o sistema emite a 10% e cobra 10% em todas as parcelas; o percentual que a política mandaria aplicar não fica registrado em lugar nenhum, e não há como saber depois qual teria sido.
  • O número errado é cobrado o contrato inteiro. A mensalidade é congelada na emissão e vale para todas as parcelas da vigência; um percentual errado no momento da emissão não é um erro de uma parcela, é de doze ou trinta.

2. Quem sente

  • ANALYST, e o ADMIN_TENANT quando aprova — é quem decide o preço de cada garantia, e hoje não tem onde decidir. Sente em toda aprovação: escolher a mensalidade é parte do caminho obrigatório de aprovar uma análise, não uma exceção.
  • ADMIN_TENANT, ao configurar — é quem traduz a política comercial (PF 8–11%, PJ 15–18%) em parâmetro, e hoje só consegue registrar metade dela.
  • O inquilino, indiretamente — é quem paga a mensalidade. Não usa o sistema, mas é ele que recebe a cobrança com o percentual errado. Quando o tomador é PJ, o erro é sistemático, não eventual.
  • A imobiliária (AGENCY_USER, AGENCY_MANAGER), indiretamente — é o canal que apresenta a proposta ao inquilino e, conforme a parceria, cobra a mensalidade junto com o aluguel e repassa. Se o valor que ela comunicou não é o que o sistema emite, a correção passa por ela. Ela não decide a taxa — a decisão é da garantidora.

Alcance: caminho obrigatório. Toda análise aprovada vira, ou pode virar, uma garantia com mensalidade; não há aprovação em que a pergunta "qual percentual?" não exista. Volume não é medido aqui: a garantidora em produção começou a operar em outubro de 2026 e ainda não há histórico de aprovações para contar.

3. A jornada de hoje

O gatilho é uma análise de crédito chegando ao analista para decisão.

  1. O ADMIN_TENANT configurou uma vez a taxa de garantia padrão e uma faixa mínima e máxima. A faixa é uma só, para qualquer tomador.
  2. O analista abre a análise, confere documentos e participantes, e vê o resumo financeiro — calculado com a taxa padrão da garantidora, qualquer que seja o tomador.
  3. O analista aprova. Na aprovação ele informa parecer, justificativa e a taxa de adesão (spec 0056). Não informa percentual de mensalidade — a tela não tem o campo. A conferência contra a faixa do passo 1 existe no sistema, mas só seria acionada se um percentual chegasse; como nenhum chega, ela nunca roda. ← quebra aqui: é o único momento em que o analista está olhando o caso, e é justamente o momento em que ele não tem como registrar o preço que decidiu.
  4. Entre a aprovação e a emissão, se a conversa com a imobiliária ou com o inquilino muda o preço, não há o que ajustar no sistema. ← quebra aqui também: o preço só pode mudar mexendo na configuração da garantidora inteira.
  5. A garantia é emitida com a taxa padrão, e a mensalidade fica congelada para todas as parcelas da vigência.
  6. As parcelas saem com esse valor. A primeira, no pagamento inicial, e as mensais seguintes, todas com a mesma mensalidade congelada na emissão.

Não há passo fora do sistema: o usuário informou que ninguém ajusta o preço caso a caso — não porque não seja preciso, mas porque não há onde. A política de faixa por tipo de tomador fica no papel.

O que já se tentou: a resposta do usuário em 2026-10-12 é que toda garantia sai com a taxa padrão — ninguém ajusta caso a caso. Não há contorno em uso: nem mudar a configuração antes de emitir e depois voltar, nem planilha paralela. A política de faixa por tipo de tomador existe no negócio e não é aplicada.

O que existe e não se usa: a configuração já tem um mínimo e um máximo (bloco "Taxas — Analistas"), e o texto dele diz que é a faixa que o analista pode aplicar ao aprovar. O caminho por trás da tela também existe: a aprovação aceita um percentual, recusa o que estiver fora da faixa, grava-o na decisão, e a emissão da garantia usa esse percentual no lugar do padrão. O que quebra é a ponta e a forma: nenhuma tela oferece o campo, a faixa é uma só para PF e PJ, não há como rever o percentual depois de aprovar, e não há prévia em reais. Isto importa para o desenho: parte do que a solução precisa já está construída, e a pergunta aberta é o que fazer com a faixa única e com o percentual da decisão quando passarem a existir duas faixas.

O que muda depois do contrato: nada, e isso é desejado. Emitida a garantia, a mensalidade fica congelada; mudar o preço de um contrato vigente exige cancelar e emitir outro. Isto não é dor — é a regra, e precisa continuar sendo.

4. Resultado esperado

  • A garantidora registra duas políticas de mensalidade, uma para pessoa física e uma para pessoa jurídica, cada uma com seu percentual sugerido e seus limites inferior e superior — e quem configura reconhece os blocos pelo nome do negócio ("mensalidade" e "atraso"), num lugar só.
  • Toda aprovação registra o percentual da mensalidade, dentro da faixa do tipo do tomador. O que o analista decidiu é o que o contrato cobra; não existe mais garantia emitida com um percentual que ninguém escolheu.
  • Uma PJ nunca sai com a faixa de PF, e vice-versa — é verificável abrindo qualquer garantia emitida: o percentual está dentro da faixa do tipo do tomador.
  • O analista vê o valor em reais antes de gravar — muda o percentual e vê a parcela resultante, sem precisar salvar para descobrir quanto deu.
  • Entre aprovar e emitir, o percentual pode ser revisto por quem pode aprovar; depois de emitida a garantia, não pode mais — vale para todas as parcelas da vigência.

Como se sabe que resolveu: emitir uma garantia de tomador PJ e outra de tomador PF, cada uma com um percentual diferente do sugerido, e conferir que cada uma cobra, em todas as parcelas, o percentual escolhido — e que um percentual fora da faixa do tipo não passa.

5. Fora de escopo

  • Mudar a mensalidade de garantia já emitida. Contrato fechado não muda; o caminho é cancelar e emitir outro. Não entra aditivo, nem reajuste, nem renegociação.
  • Faixas por imobiliária. A spec 0056 deu à imobiliária uma regra própria de taxa de adesão; foi cogitado fazer o mesmo com a mensalidade e fica de fora — o usuário descreveu a política como da garantidora, por tipo de tomador, e não por canal.
  • Mais tipos de tomador que PF e PJ, ou faixa por outro critério (valor do aluguel, tipo de imóvel, score). O cadastro de inquilino tem só os dois tipos.
  • Alterar multa e juros por atraso. Eles mudam de lugar e de nome junto com a reorganização da configuração, mas o comportamento deles (spec 0054) não muda.
  • A taxa de adesão. Continua como a spec 0056 deixou; esta spec só põe a mensalidade ao lado dela na aprovação.
  • Recalcular garantias já emitidas com os novos parâmetros. As garantias existentes seguem com o percentual com que foram emitidas.
  • Quem decide o tipo do tomador. É o tipo cadastrado do locatário principal da análise; corresponsáveis e demais locatários não mudam a faixa. Corrigir um cadastro com tipo errado é edição do inquilino, não desta spec.

6. Revisão do problema

Preenchido pelo laço do /spec new, rubrica .claude/rubrics/problema.md. Registrar todas as rodadas, inclusive as reprovadas.

Rodada Critical Important Minor Nota Veredicto
1 0 1 1 8 Aprovada

Resultado: aprovada na rodada 1.

Pendências aceitas: nenhuma. Os dois apontamentos foram corrigidos no texto depois da aprovação: o Important (a jornada dizia que "não há onde" informar o percentual, quando a aprovação já aceita, valida e propaga um percentual por trás da tela — o que quebra é a tela, a faixa única e a falta de revisão e de prévia) e o Minor (o título de uma consequência afirmava uma direção que o texto não sustentava).


Parte II — A experiência

Não preencher antes da revisão da seção 6 estar aprovada.

7. Jornada pretendida

São três momentos, e cada um responde a um ponto de quebra da seção 3: a garantidora registra as duas políticas (configuração); o analista escolhe o percentual ao aprovar, vendo o valor em reais (passo 3 da jornada de hoje); e quem pode aprovar revê o percentual até a garantia ser emitida (passo 4). Depois da emissão, nada muda — e a tela diz isso.

Os nomes desta parte. Na tela, o percentual se chama mensalidade — é a palavra do negócio, e é como o resumo financeiro já chama o valor em reais ("Mensalidade de garantia"). O percentual que vem preenchido é a mensalidade sugerida; os limites são a mínima e a máxima; o conjunto mínima–máxima de um tipo é a faixa. O tipo do tomador é sempre escrito por extenso na interface ("pessoa física", "pessoa jurídica"), com PF/PJ só onde falta espaço.

Momento A — A garantidora configura as duas políticas

  • Ponto de entrada: menu Parâmetros (as configurações da garantidora), como hoje.
  • Quem: quem já edita os parâmetros hoje (ADMIN_TENANT).
  • Jornada, caso feliz:
  • Abre Parâmetros. Os dois blocos de hoje — "Taxas" e "Taxas — Analistas" — viraram um bloco só, chamado "Mensalidade e atraso".
  • Dentro dele, três grupos, cada um com um subtítulo:
    • Mensalidade — pessoa física: sugerida, mínima e máxima (%).
    • Mensalidade — pessoa jurídica: sugerida, mínima e máxima (%).
    • Atraso: multa (%) e juros de mora (% ao mês) — os mesmos dois campos de hoje, com o mesmo comportamento da spec 0054.
  • Preenche, por exemplo, PF sugerida 10%, mínima 8%, máxima 11%; PJ sugerida 16%, mínima 15%, máxima 18%.
  • Salva com o botão de salvar dos Parâmetros, como hoje.
  • Custo de uso: seis números para a mensalidade, uma vez, quando a política muda. O texto de apoio do bloco diz em uma frase o que eles governam: "A mensalidade é um percentual do Pacote Locatício. O analista escolhe o percentual ao aprovar, dentro da faixa do tipo do inquilino principal; a sugerida é a que vem preenchida."
  • Validação, no próprio campo, ao salvar: a mínima não pode ser maior que a máxima, e a sugerida tem de estar entre as duas — a mensagem sai debaixo do campo errado e diz o que corrigir ("A sugerida para pessoa física precisa estar entre a mínima (8%) e a máxima (11%)"). Os três campos de cada tipo são obrigatórios: uma faixa pela metade deixaria a aprovação sem limite.
  • O que deixa de existir na tela: a "Taxa de garantia (%)" única e a faixa única. Não há mais um percentual que vale para todo mundo.

Momento B — O analista escolhe a mensalidade ao aprovar

  • Ponto de entrada: a tela da análise de crédito, no painel do parecer, quando a análise está em análise ou devolvida e quem vê pode decidir — o mesmo lugar onde hoje ficam o parecer, as notas internas e a taxa de adesão.
  • Jornada, caso feliz:
  • O analista abre a análise. No painel do parecer, logo abaixo da Taxa de adesão (R$), há o campo Mensalidade (%), já preenchido com a sugerida do tipo do inquilino principal.
  • Debaixo do campo, uma linha diz de onde o número vem e quanto ele dá: "Pessoa física · faixa de 8% a 11% · R$ 300,00 por mês". O valor em reais é o Pacote Locatício da análise vezes o percentual.
  • O analista muda o percentual — digamos para 9,5%. A linha de baixo se recalcula enquanto ele digita, sem salvar nada: "… · R$ 285,00 por mês". O resumo financeiro da mesma tela (bloco "Situação financeira") também passa a mostrar a mensalidade, o total da vigência e o pagamento inicial com 9,5%, para quem rolar até ele.
  • Clica Aprovar, no cabeçalho, como hoje. A confirmação de aprovação — que já resume o parecer e a taxa de adesão — ganha a linha "Mensalidade: 9,5% · R$ 285,00 por mês".
  • Confirma. A análise fica aprovada com a mensalidade de 9,5%.
  • Custo de uso: nenhum, no caso comum — o campo já vem com a sugerida, e aprovar sem tocar nele aprova com ela. Mexe quem quer outro número.
  • O que o sistema já sabe e não pergunta: o tipo do inquilino principal (está no cadastro dele), o Pacote Locatício (está na análise) e a faixa (está nos Parâmetros). O analista não escolhe "PF ou PJ" — o tipo vem do cadastro.
  • Fora da faixa: se ele digita 12% numa pessoa física, o campo fica em erro na hora, com "Fora da faixa de pessoa física: de 8% a 11%", a linha do valor em reais desaparece, e o Aprovar não confirma: a confirmação mostra o mesmo erro e o botão de confirmar fica desabilitado até o número voltar para a faixa.
  • Salvar rascunho, que já existe no painel, guarda parecer e notas como hoje; a mensalidade escolhida se grava na aprovação, junto com a taxa de adesão — é assim que a taxa de adesão já funciona, e as duas se decidem no mesmo gesto.

Momento C — Rever a mensalidade entre aprovar e emitir

  • Ponto de entrada: a mesma tela da análise, agora aprovada e ainda sem garantia emitida. O painel do parecer, que hoje fica só de leitura depois da aprovação, mostra a linha "Mensalidade aprovada: 9,5% a.m. · R$ 285,00 por mês" com um botão Alterar ao lado. Ela substitui a linha "Taxa aprovada" que o modo leitura do parecer tem hoje — é o mesmo dado, com o valor em reais junto; as duas não coexistem.
  • Quem vê o Alterar: quem pode aprovar análises (decisão do usuário em 2026-10-12). Quem vê o parecer sem poder aprovar vê a linha, sem o botão.
  • Quem não vê o parecer — a imobiliária (o parecer é deliberação interna da garantidora e continua fechado para ela): vê a mensalidade escolhida em dois lugares, só leitura (decisão do usuário em 2026-10-12): no resumo financeiro do bloco "Situação financeira" da análise, que passa a mostrar a mensalidade com o percentual escolhido em vez do padrão, e, depois da emissão, na tela da garantia, que ela já lê. É o que ela precisa para comunicar o valor ao inquilino. A imobiliária não emite garantia (não tem a permissão de emitir), então o diálogo Emitir garantia não é dela — a resposta do usuário mencionava a emissão sob a premissa errada de que ela emitia, corrigida na Parte III.
  • Jornada, caso feliz:
  • Quem pode aprovar clica Alterar. A linha vira o mesmo campo do Momento B, já com 9,5%, com a mesma linha de faixa e valor em reais recalculando enquanto digita.
  • Muda para 10,5%. Vê "… · R$ 315,00 por mês"; o resumo financeiro acompanha.
  • Clica Salvar (ou Cancelar, que volta ao 9,5% sem gravar nada).
  • Salvo, a linha volta ao modo leitura com 10,5% e, embaixo, "Definida por Fulana em 12/10/2026 14:32" — quem aprovou e quem alterou podem ser pessoas diferentes, e a tela não pode atribuir a uma o número da outra.
  • Na emissão: o diálogo Emitir garantia já mostra a taxa que vai ser congelada (hoje "Taxa"); passa a mostrar "Mensalidade: 10,5% · R$ 315,00 por mês", só leitura — o diálogo de emissão não vira um segundo lugar de decidir o preço. A frase abaixo do valor depende de quem emite: para quem pode aprovar, "Para mudar, cancele e use Alterar no parecer."; para quem emite sem poder aprovar (o operador), "Definida pela garantidora na aprovação. Se o valor não é o combinado, fale com a garantidora antes de emitir." — nunca uma instrução para um botão que a pessoa não vê.
  • Depois de emitida a garantia: o botão Alterar some. A linha fica só de leitura, com o texto "Garantia emitida — a mensalidade vale para todas as parcelas e não muda mais. Para outro valor, a garantia precisa ser cancelada e uma nova emitida." A tela da garantia mostra o percentual com que ela foi emitida, como já mostra hoje.

Análises que já estão aprovadas quando isto entrar no ar

Uma análise aprovada antes desta feature e ainda sem garantia não tem mensalidade escolhida. No painel do parecer ela aparece como "Mensalidade: não escolhida na aprovação — será usada a sugerida para pessoa jurídica (16%) · R$ 480,00 por mês", com o mesmo Alterar do Momento C. Ou seja: passa a valer a política nova, e quem pode aprovar ainda pode ajustar antes de emitir (decisão do usuário em 2026-10-12). Garantias já emitidas não mudam.

7.1 Desktop

Parâmetros — bloco "Mensalidade e atraso". Um painel (o FormPanel que os Parâmetros já usam), na mesma posição em que hoje está o bloco "Taxas", e o bloco "Taxas — Analistas" deixa de existir. Dentro, três grupos empilhados, cada um com subtítulo pequeno no padrão dos outros grupos da tela:

  • Mensalidade — pessoa física: três campos lado a lado numa linha — Sugerida (%), Mínima (%), Máxima (%).
  • Mensalidade — pessoa jurídica: a mesma linha de três campos.
  • Atraso: Multa por atraso (%) e Juros de mora (% ao mês), lado a lado, como hoje.

Tudo visível de uma vez sem rolar dentro do bloco: são oito campos em três linhas. A leitura PF-sobre-PJ, com as colunas alinhadas, é o que permite comparar as duas faixas num relance.

Tela da análise — painel do parecer. Em análise: Parecer do analista, Notas internas, Taxa de adesão (R$) e Mensalidade (%) empilhados na coluna do painel, como os campos de hoje; a linha de faixa e valor em reais fica no texto de apoio do campo. O resumo financeiro, mais abaixo na página, acompanha o número — mas o analista não precisa rolar até ele para saber quanto dá: o valor em reais está colado ao campo. Ações de decisão continuam no cabeçalho.

Aprovada e sem garantia: os dados de leitura do parecer, como hoje, e a linha da mensalidade com Alterar à direita, alinhado à linha. Em modo de edição, Salvar e Cancelar ficam logo abaixo do campo, à esquerda, no padrão do "Salvar rascunho" do mesmo painel. São três cliques do começo ao fim: Alterar, digitar, Salvar.

7.2 Mobile (375px)

Parâmetros. O painel vira uma coluna: cada grupo com o subtítulo e seus campos empilhados, um por linha, largura inteira — é o que o grid dos Parâmetros já faz em telas estreitas. Os três campos de um tipo ficam juntos sob o subtítulo, na ordem Sugerida, Mínima, Máxima, para a validação "a sugerida entre as duas" ser lida de cima para baixo. Os campos abrem o teclado numérico com vírgula. Configurar pelo celular é raro, mas não há nada escondido: os oito campos estão lá.

Tela da análise — aprovação. A aprovação acontece às vezes pelo celular (resposta do usuário em 2026-10-12), e é aqui que o mobile pesa:

  • O valor em reais fica colado ao campo, não no resumo. Em 375px o bloco "Situação financeira" está várias telas abaixo do parecer — consultas, política, documentos entre os dois. Se a prévia vivesse só no resumo, o analista no celular mudaria o percentual sem ver o efeito. É por isso que a linha "Pessoa física · faixa de 8% a 11% · R$ 285,00 por mês" fica no texto de apoio do próprio campo, nos dois viewports.
  • No celular essa linha quebra em duas quando não cabe: a faixa em cima, o valor em reais embaixo, sem cortar o número.
  • O campo abre o teclado numérico com vírgula. Com o teclado aberto, o campo e a linha de baixo ficam visíveis (o campo é o último do painel antes do "Salvar rascunho" — a tela rola para mantê-lo acima do teclado, como os campos de texto de hoje).
  • A confirmação de aprovação continua como é hoje no celular — um diálogo centrado, de largura inteira, não tela cheia. A linha "Mensalidade" entra no resumo dela como as outras e, como elas, quebra o valor para a linha de baixo quando não cabe ao lado do rótulo.
  • Alterar, depois de aprovada: o botão fica abaixo da linha da mensalidade, largura inteira, com altura de toque de 44px — ao lado da linha ele espremeria o valor em 375px. Em edição, Salvar e Cancelar ficam lado a lado, cada um com metade da largura.
  • Nada some no celular. São os mesmos campos e a mesma informação; muda o empilhamento e onde o botão fica.

PWA: sem impacto próprio — nenhuma tela nova nem tela offline; o bundle novo chega pela atualização normal do app instalado.

7.3 Estados

  • Parâmetros carregando: o painel mostra o carregamento que os Parâmetros já mostram hoje para a tela toda.
  • Parâmetros com valor inválido ao salvar: erro debaixo do campo, com o que corrigir (Momento A). Nada é salvo enquanto houver erro.
  • Painel do parecer, faixa ainda carregando: o campo Mensalidade aparece já preenchido assim que a faixa chega; antes disso, fica desabilitado com "Carregando a faixa…" no texto de apoio.
  • Painel do parecer, faixa não carregou (erro): o campo fica desabilitado com "Não foi possível carregar a faixa de mensalidade. Tentar novamente", e o "Tentar novamente" é um link que recarrega. O Aprovar continua disponível: aprovar sem a faixa carregada aprova com a sugerida do tipo, que é o mesmo que aprovar sem tocar no campo — e a confirmação diz isso ("Mensalidade: a sugerida para pessoa física"), em vez de mostrar um número que a tela não conseguiu ler.
  • Alterar com a faixa não carregada (Momento C): o Alterar abre o campo, mas desabilitado, com o mesmo "Não foi possível carregar a faixa de mensalidade. Tentar novamente"; o Salvar fica desabilitado até a faixa chegar. Ao contrário da aprovação, aqui não há o que fazer sem a faixa: a mensalidade aprovada já existe, e manter o que está é o mesmo que não alterar.
  • Pacote Locatício ausente (análise antiga sem pacote registrado): o campo funciona e a faixa aparece; a parte do valor em reais diz "sem Pacote Locatício para calcular".
  • Fora da faixa: erro no campo, sem valor em reais, confirmação bloqueada (Momento B). No Momento C, o Salvar fica desabilitado e o erro é o mesmo.
  • Salvar a alteração falhou (Momento C): o campo continua em edição com o número digitado, e uma mensagem logo abaixo diz o motivo e oferece tentar de novo. Se o motivo é que a garantia foi emitida nesse meio-tempo por outra pessoa, a mensagem diz isso ("A garantia desta análise acabou de ser emitida; a mensalidade não pode mais ser alterada.") e a tela recarrega para o modo leitura.
  • A faixa mudou depois da aprovação: a mensalidade aprovada continua valendo — foi uma decisão, e a emissão a usa. Se ela ficou fora da faixa atual do tipo, a linha da mensalidade ganha um aviso, sem bloquear: "Fora da faixa atual de pessoa física (9% a 12%). A emissão vai usar 8,5%, como aprovado — use Alterar para revisar."
  • O tipo do inquilino principal mudou depois da aprovação (o cadastro foi corrigido de PF para PJ): mesma regra e mesmo aviso — a mensalidade aprovada vale, e o aviso aponta que ela está fora da faixa do tipo atual.
  • Sem permissão: quem vê o parecer e não pode aprovar vê a mensalidade só como leitura no painel do parecer, sem campo e sem Alterar. Quem não vê o parecer — a imobiliária — não vê o painel, como hoje; vê a mensalidade escolhida no resumo financeiro e, depois da emissão, na garantia (Momento C). Quem não vê a análise não chega a esta tela — o comportamento de hoje.
  • Vazio: não se aplica — toda análise tem inquilino principal e, portanto, um tipo e uma faixa.

8. Revisão da experiência

Preenchido pelo laço do /spec new, rubrica .claude/rubrics/experiencia.md.

Rodada Critical Important Minor Nota Veredicto
1 0 1 4 8 Aprovada

Resultado: aprovada na rodada 1.

Pendências aceitas: nenhuma. Todos os apontamentos foram corrigidos no texto depois da aprovação. O Important pedia uma decisão do usuário: a imobiliária não vê o parecer, então não veria a mensalidade escolhida — respondido em 2026-10-12 que ela a vê, só leitura, no resumo financeiro e no diálogo de emissão (Momento C). Os Minor: a confirmação de aprovação não é tela cheia no celular (a 7.2 dizia que era); a linha "Mensalidade aprovada" substitui a "Taxa aprovada" de hoje; a frase do diálogo de emissão para quem emite sem poder aprovar; e o estado de faixa não carregada no Momento C.


Parte III — Detalhamento

Não preencher antes das revisões das seções 6 e 8 estarem aprovadas.

Vocabulário técnico desta parte. Na interface o percentual é "mensalidade"; no código ele continua sendo a taxa da garantia (guarantee_rate_percent), que é o nome que a Guarantee, a Decision, o pricing.py e a resposta de simulação já usam. Não se renomeia o que já existe — só o que muda de forma (a faixa única vira duas). O tomador é o locatário principal da análise (CreditAnalysisParticipant com role=LESSEE e is_primary=True), e o tipo do tomador é o Renter.renter_type dele (PF | PJ, apps/api/app/models/renter.py:27).

9. Regras de negócio

Parâmetros

  • RN1. Seis parâmetros substituem três. TenantSettings deixa de ter guarantee_rate_percent, min_guarantee_rate_percent e max_guarantee_rate_percent (apps/api/app/models/tenant_settings.py:52-60) e passa a ter, para cada tipo de tomador, sugerida, mínima e máxima: pf_guarantee_rate_percent, pf_min_guarantee_rate_percent, pf_max_guarantee_rate_percent, pj_guarantee_rate_percent, pj_min_guarantee_rate_percent, pj_max_guarantee_rate_percent — todos Numeric(5, 2), não anuláveis, cada um entre 0.01 e 100.00.
  • RN2. A faixa de cada tipo é coerente, sempre. Para cada tipo, depois de aplicada a alteração sobre o que está gravado: mínima ≤ sugerida ≤ máxima. O PATCH /api/v1/settings valida o estado resultante (o enviado mesclado ao gravado), não só o enviado — hoje o TenantSettingsUpdate (apps/api/app/schemas/tenant_settings.py:192-195) não valida a relação entre os três campos, e um PATCH só com a mínima pode deixá-la acima da máxima. Violação → 422 GUARANTEE_RATE_RANGE_INVALID, nada gravado, com um item de details por tipo que quebrou, apontando um campo só, por esta ordem:
  • mínima > máxima → o campo é a mínima do tipo, mensagem "A mínima para pessoa física (12%) não pode ser maior que a máxima (11%)";
  • senão, sugerida fora de [mínima, máxima] → o campo é a sugerida do tipo, mensagem "A sugerida para pessoa física precisa estar entre a mínima (8%) e a máxima (11%)".

O campo apontado independe de quais campos vieram no corpo: a regra olha o estado resultante, e a tela põe a mensagem debaixo do campo que o details nomeia. - RN3. Nenhum dos seis volta a vazio. null explícito em qualquer um → 422 FIELD_REQUIRED com details no campo, no mesmo molde da spec 0056 em apps/api/app/services/tenant_settings_service.py:67-79 (o exclude_none descartaria o null em silêncio). Os três campos antigos saem do TenantSettingsUpdate e do TenantSettingsResponse; enviá-los passa a ser ignorado, como os campos que a spec 0006 removeu. - RN4. Valores de partida (decisão do usuário em 2026-10-12): PF sugerida 8,00, mínima 8,00, máxima 11,00; PJ sugerida 15,00, mínima 15,00, máxima 18,00. Valem para toda garantidora existente (a migração as grava, inclusive na produção) e para toda garantidora nova (_default_settings em apps/api/app/services/onboarding_service.py:710-716, que hoje grava 10/8/14). Depois disso, o ADMIN_TENANT edita. - RN5. Multa e juros não mudam. late_fee_percent, interest_percent_month e late_fee_grace_days seguem com o comportamento da spec 0054; só mudam de bloco na tela.

O tipo e a faixa de uma análise

  • RN6. O tipo do tomador decide a faixa. O tipo é lido no momento do uso — na aprovação, na alteração, na emissão e em cada leitura da análise —, do cadastro atual do locatário principal. Corresponsáveis e locatários não principais não contam. A análise sem locatário principal (estado que o fluxo não produz, mas que o banco não impede) usa o primeiro locatário na ordem de CreditAnalysisParticipantRepository.get_lessees (apps/api/app/repositories/credit_analysis_participant_repo.py:38-50), que é o que a emissão já faz para escolher o primary_lessee_id; sem locatário nenhum, a faixa é a de PF. A escolha de faixa é uma função pura, faixa_da_mensalidade(settings, renter_type) → (sugerida, mínima, máxima), em apps/api/app/domain/mensalidade.py (arquivo novo).

Aprovar

  • RN7. Toda aprovação grava uma taxa. No POST /credit-analyses/{id}/decision/approve, approved_guarantee_rate_percent continua opcional no corpo, mas a Decision aprovada sempre sai com approved_guarantee_rate_percent preenchido:
  • informado → validado contra a faixa do tipo do tomador (RN6). Fora → 422 RATE_OUT_OF_RANGE, mensagem "Fora da faixa de pessoa física: de 8% a 11%" (o tipo por extenso e a faixa), nada gravado;
  • omitido → grava-se a sugerida do tipo do tomador naquele momento.

Garantidora sem TenantSettings (caso que o onboarding não produz, mas que o approve hoje tolera com if settings: em apps/api/app/services/decision_service.py:226) → 422 SETTINGS_NOT_FOUND, como a emissão já faz (apps/api/app/services/guarantee_service.py:181-185): sem parâmetros não há faixa nem sugerida, e aprovar sem taxa recriaria a decisão sem preço que esta spec elimina.

Hoje a validação usa a faixa única (apps/api/app/services/decision_service.py:223-235) e, omitido, não grava nada — a emissão resolve depois. - RN8. A aprovação registra quem fixou a taxa. Decision ganha guarantee_rate_set_by_id (FK users.id, ondelete=SET NULL, anulável) e guarantee_rate_set_at (timestamptz, anulável). A aprovação os preenche com quem aprova e o instante. São eles que alimentam o "Alterada por … em …" da Parte II.

Alterar entre aprovar e emitir

  • RN9. Endpoint próprio para alterar. PATCH /api/v1/credit-analyses/{id}/decision/guarantee-rate, corpo { "guarantee_rate_percent": "10.50" } (obrigatório, 0.01–100.00). Pré-condições, conferidas nesta ordem, cada uma com seu código:
  • quem chama não é ADMIN_GLOBAL — senão 403 PLATFORM_ADMIN_CANNOT_PRICE, antes de resolver a análise, como a emissão faz com as guardas dela (apps/api/app/services/guarantee_service.py:143-148): o ADMIN_GLOBAL recebe 403 para análise existente e inexistente, sem que a resposta revele qual é qual;
  • análise no escopo de quem chama (seção 10) — senão 404;
  • análise em APPROVED e decisão em APPROVED — senão 422 ANALYSIS_NOT_APPROVED;
  • sem garantia emitida para a análise — senão 409 GUARANTEE_EXISTS, mensagem "A garantia desta análise acabou de ser emitida; a mensalidade não pode mais ser alterada.";
  • taxa dentro da faixa do tipo do tomador (RN6) — senão 422 RATE_OUT_OF_RANGE, mesma mensagem da RN7.

Passando, grava approved_guarantee_rate_percent, guarantee_rate_set_by_id (quem chama) e guarantee_rate_set_at (agora), e registra no AuditLog (entity_type="decision", action="GUARANTEE_RATE_CHANGED", payload com from e to). Mandar o mesmo valor que já está gravado é aceito e não gera auditoria. - RN10. Alterar e emitir não se atravessam. A alteração (RN9) e a emissão (GuaranteeService.create) leem a Decision com SELECT … FOR UPDATE e populate_existing, antes de checar a existência da garantia (na alteração) ou de ler a taxa (na emissão). O populate_existing não é detalhe: na alteração, o _get_decision já pôs a Decision no identity map da sessão, e uma releitura travada sem ele devolveria o objeto antigo sem refrescar os atributos — a trava seria tomada, mas o from da auditoria e a comparação "mesmo valor" (RN9) usariam o valor de antes da espera. É o padrão de apps/api/app/repositories/role_repo.py:92. Na emissão a Decision só é lida uma vez (apps/api/app/services/guarantee_service.py:174), e a leitura travada a substitui. Com isso, quem chega segundo espera o outro terminar: se a emissão venceu, a alteração vê a garantia e devolve 409; se a alteração venceu, a emissão lê a taxa nova. Sem a trava, a emissão poderia ler 9,5%, a alteração gravar 10,5% e responder 200, e a garantia sair a 9,5% com a tela dizendo 10,5%. Hoje a emissão não trava nada (apps/api/app/services/guarantee_service.py:160-175).

A taxa em vigor e o que a usa

  • RN11. Taxa em vigor de uma análise: a approved_guarantee_rate_percent da decisão, quando houver; senão, a sugerida do tipo atual do tomador. A segunda vale para as análises aprovadas antes desta spec e ainda sem garantia (decisão do usuário em 2026-10-12: passam a usar a política nova) e para análises ainda não decididas. Não há mais "taxa padrão do tenant".
  • RN12. A emissão usa a taxa em vigor, e não a revalida. GuaranteeService.create troca o settings.guarantee_rate_percent do fallback (apps/api/app/services/guarantee_service.py:217-221) pela RN11. Não confere a taxa decidida contra a faixa atual: foi uma decisão, e a mudança posterior de faixa ou de tipo do tomador não a invalida (Parte II, 7.3). A garantia congela a taxa em guarantee_rate_percent e a mensalidade em monthly_value, como hoje, e todas as parcelas saem de monthly_value (apps/api/app/services/guarantee_service.py:794-800).
  • RN13. A simulação espelha a emissão. GuaranteeService.simulate com análise usa a RN11 no lugar do settings.guarantee_rate_percent (apps/api/app/services/guarantee_service.py:482 e 505-507). Sem análise (simulação avulsa), usa a sugerida de PF — não há tomador de onde ler o tipo — e o corpo da simulação não ganha campo de tipo: a simulação avulsa não tem tela que a chame com tipo, e acrescentar campo para isso é escopo que nenhuma dor pediu.
  • RN14. Garantia emitida não muda de taxa. Nenhum endpoint altera Guarantee.guarantee_rate_percent ou monthly_value — já é assim, e esta spec não abre caminho. Mudar o preço de contrato emitido é cancelar e emitir outro (seção 5).
  • RN15. O snapshot financeiro da análise acompanha a taxa. O _apply_financial_snapshot (apps/api/app/services/credit_analysis_service.py:964-1024) troca settings.guarantee_rate_percent pela RN11. E a aprovação (RN7) e a alteração (RN9) atualizam, no mesmo commit, só a parte do snapshot que depende da taxa: financial_guarantee_rate_percent, financial_monthly_value (Pacote × taxa, arredondado como em apps/api/app/services/pricing.py:64) e financial_first_month_upfront (a nova mensalidade, se o snapshot cobrava o primeiro mês à vista — isto é, se o valor gravado é maior que zero; senão fica como está). Os demais campos do snapshot (LMI, adesão, custos de saída) não são recalculados aqui: a aprovação e a alteração decidem o preço mensal, não reabrem o resto.

A taxa na resposta da análise

  • RN16. GET /credit-analyses/{id} ganha o objeto guarantee_rate, calculado na leitura (como o initial_fee da spec 0056 em apps/api/app/services/credit_analysis_service.py:1065-1118, o _origem_da_taxa):
  • renter_type — tipo atual do tomador (RN6);
  • suggested_percent, min_percent, max_percent — a faixa desse tipo hoje;
  • approved_percent — a da decisão, ou null;
  • effective_percent e source (GUARANTEE | APPROVED | SUGGESTED) — a RN11, com uma precedência a mais: emitida a garantia, vale a taxa dela (GUARANTEE, RN14), e monthly_value é o da garantia. Sem isto, uma garantia emitida antes desta spec (decisão sem taxa) apareceria na análise com a sugerida de hoje ao lado de "não muda mais";
  • monthly_value — financial_rental_package × effective_percent / 100, arredondado como no pricing.py; null sem Pacote Locatício;
  • within_current_range — se effective_percent está na faixa atual do tipo;
  • set_by_name e set_at — de guarantee_rate_set_by_id/_at (RN8), ou null;
  • locked — true quando já há garantia emitida para a análise.

É a fonte do que a tela mostra sobre a mensalidade, antes e depois da aprovação — inclusive no resumo financeiro, que a imobiliária vê (Parte II, Momento C). A regra de quem vê o objeto e quais campos está na seção 10. - RN17. Prévia na tela, sem gravar. Enquanto o analista digita, o valor em reais é calculado no navegador: Pacote × percentual ÷ 100, arredondado a duas casas com meio para cima, que é o arredondamento do pricing.py (_round). A faixa vem do guarantee_rate (RN16). Nenhuma chamada à API por tecla. O número gravado é o que o servidor calcula; a prévia só o antecipa.

10. Autorização e isolamento

10.1 Matriz de papéis

"Aprovar" e "alterar" exigem as mesmas duas permissões — decisions:update e credit_analyses:approve —, porque são a mesma decisão em dois momentos (decisão do usuário em 2026-10-12: altera quem pode aprovar).

Papel Pode Não pode
ADMIN_GLOBAL ler o objeto guarantee_rate de análise de qualquer tenant, sem a faixa (RN16 com suggested_percent/min_percent/max_percent nulos, como o initial_fee.rule da 0056); aprovar, como hoje alterar a taxa (RN9) — recusa por guarda de código, 403 PLATFORM_ADMIN_CANNOT_PRICE (decisão do usuário em 2026-10-12); editar os parâmetros (o PATCH /settings já exige ADMIN_TENANT de sistema)
ADMIN_TENANT editar os seis parâmetros; aprovar com taxa; alterar a taxa até a emissão; ler o objeto completo alterar depois da emissão (409); alterar análise de outro tenant (404)
ANALYST aprovar com taxa; alterar até a emissão; ler o objeto completo editar parâmetros (403); alterar depois da emissão (409); outro tenant (404)
OPERATOR ler o objeto completo; emitir a garantia com a taxa em vigor aprovar e alterar a taxa (403 — não tem credit_analyses:approve); editar parâmetros (403)
VIEWER ler o objeto completo alterar (403); editar parâmetros (403)
AGENCY_USER / AGENCY_MANAGER ler o objeto guarantee_rate das análises da própria imobiliária, e a taxa da garantia emitida, como hoje alterar (403 — sem decisions:*); ler análise de outra imobiliária (404); ler o parecer (como hoje)

10.2 Permissões

Nenhuma permissão nova. Por endpoint:

  • PATCH /settings — inalterado: require_system_role("ADMIN_TENANT") (apps/api/app/api/v1/routers/tenant_settings.py:156).
  • POST /credit-analyses/{id}/decision/approve — inalterado: require_all_permissions(("decisions", "update"), ("credit_analyses", "approve")) (apps/api/app/api/v1/routers/decisions.py:140).
  • PATCH /credit-analyses/{id}/decision/guarantee-rate (novo) — o mesmo require_all_permissions(("decisions", "update"), ("credit_analyses", "approve")), mais a guarda de código do ADMIN_GLOBAL (10.5). No rbac_seed.py, quem tem as duas hoje: ADMIN_TENANT (apps/api/app/db/rbac_seed.py:277), ANALYST (:333) e o ADMIN_GLOBAL por compreensão (:239) — que a guarda recusa.
  • GET /credit-analyses/{id} — inalterado (credit_analyses:read); o objeto novo vem dentro da resposta.
  • POST /guarantees e POST /guarantees/simulate — inalterados.

10.3 Isolamento por garantidora (tenant)

  • O endpoint novo não recebe FK no corpo — só o percentual. A análise vem do path e é resolvida pelo mesmo caminho do approve, DecisionService._get_decision (apps/api/app/services/decision_service.py:469-479): get_by_id com o tenant_id de quem chama; análise de outro tenant → 404 NOT_FOUND, nunca 403.
  • A faixa sempre vem do tenant da análise, não do de quem chama (settings_repo.get_by_tenant(credit_analysis.tenant_id)), como o approve já faz.
  • O tomador e o tipo são lidos dos participantes da própria análise — não há id de inquilino no corpo para ser trocado.

10.4 Isolamento por imobiliária

  • O endpoint novo é inalcançável pela imobiliária por permissão (403). Mesmo assim o _get_decision mantém o recorte por partner_agency_id (apps/api/app/services/decision_service.py:474-475), que devolve 404 para análise de outra parceira — vale para um papel customizado que alguém crie com as duas permissões.
  • O objeto guarantee_rate vem dentro do GET /credit-analyses/{id}, que já recorta por imobiliária: a imobiliária só o vê nas análises dela. Ela vê a taxa e o valor (é o que ela comunica ao inquilino, Parte II) e a faixa do tipo — que ela já lê hoje em GET /settings, onde tem tenant_settings:read (apps/api/app/db/rbac_seed.py:403). Não vê o parecer, como hoje.
  • set_by_name (quem fixou a taxa) não vai para a imobiliária: é nome de pessoa da garantidora numa deliberação interna, o mesmo motivo que fecha o parecer para ela. Para AGENCY_USER/AGENCY_MANAGER, set_by_name e set_at saem null.

10.5 Plataforma × cliente (SaaS admin)

  • Alterar a taxa é decisão comercial do cliente, e o ADMIN_GLOBAL não a toma (decisão do usuário em 2026-10-12). A recusa é guarda de código no serviço, com exigir_permissao-equivalente explícito (code="PLATFORM_ADMIN_CANNOT_PRICE") — não subtração no rbac_seed, porque a fixture de teste do ADMIN_GLOBAL concede todas as permissões sem consultar o mapa (o mesmo motivo registrado em apps/api/app/db/rbac_seed.py:220-238). A permissão em si continua com ele: tirá-la quebraria a aprovação, que segue como está.
  • A aprovação pelo ADMIN_GLOBAL não muda nesta spec. Ele já aprova hoje; a RN7 só faz a aprovação dele gravar a sugerida quando omitida, como a de qualquer um. Restringir a aprovação dele é outra discussão, fora daqui.
  • Leitura: o ADMIN_GLOBAL lê análise cross-tenant como já lê; o objeto guarantee_rate sai sem a faixa (10.1), no mesmo critério do initial_fee.rule da spec 0056 (apps/api/app/services/credit_analysis_service.py:1102). A taxa e o valor ficam, porque já estão no financial_summary que ele lê hoje.
  • Nenhuma tela do SaaS admin (/app/admin/*) muda.

11. Impacto por app

apps/api

  • Modelos/migrations:
  • apps/api/app/models/tenant_settings.py — RN1.
  • apps/api/app/models/decision.py — RN8 (guarantee_rate_set_by_id, guarantee_rate_set_at); docstring da classe atualizada (a "faixa configurada" vira "a faixa do tipo do tomador").
  • Migration nova, apps/api/alembic/versions/<rev>_mensalidade_por_tipo_de_tomador.py (seção 12).
  • Endpoints:
  • PATCH /api/v1/settings — schema novo (RN1–RN3).
  • POST /api/v1/credit-analyses/{id}/decision/approve — RN7, RN8, RN15; Swagger reescrito (a faixa por tipo, a sugerida quando omitida).
  • PATCH /api/v1/credit-analyses/{id}/decision/guarantee-rate — novo, em apps/api/app/api/v1/routers/decisions.py, que já declara CommitRoute.
  • GET /api/v1/credit-analyses/{id} — objeto guarantee_rate (RN16).
  • POST /api/v1/guarantees e POST /api/v1/guarantees/simulate — RN12, RN13.
  • Regras no service:
  • apps/api/app/domain/mensalidade.py (novo) — faixa_da_mensalidade (RN6) e taxa_em_vigor (RN11), puras.
  • apps/api/app/services/tenant_settings_service.py — RN2 e RN3.
  • apps/api/app/services/decision_service.py — RN7, RN8, RN9 (método novo change_guarantee_rate), RN10 (lock), RN15, guarda do ADMIN_GLOBAL.
  • apps/api/app/services/guarantee_service.py — RN10 (lock na emissão), RN12, RN13.
  • apps/api/app/services/credit_analysis_service.py — RN15 no _apply_financial_snapshot (as leituras de settings.guarantee_rate_percent em :993 e :1006), RN16 no _build_response, e a terceira leitura do campo removido, no _origem_da_taxa (:1094) — lá a taxa só alimenta o cálculo de que se aproveita o .initial_fee, que não depende dela; passa a receber a taxa em vigor (RN11) só para o campo existir, sem efeito no resultado.
  • apps/api/app/services/onboarding_service.py — RN4.
  • apps/api/app/repositories/decision_repo.py — leitura com FOR UPDATE (RN10).
  • apps/api/app/repositories/credit_analysis_participant_repo.py — reaproveita get_lessees; sem mudança.
  • apps/api/app/services/pricing.py — sem mudança: continua sendo o cálculo da mensalidade (monthly_value) e a referência de arredondamento da prévia (RN17).
  • Schemas: apps/api/app/schemas/tenant_settings.py (Update/Response; o TenantSettingsCreate, que nenhum router usa, perde os três campos antigos junto), apps/api/app/schemas/decision.py (corpo do PATCH novo; AnalysisResponse com guarantee_rate_set_at), apps/api/app/schemas/credit_analysis.py (objeto CreditAnalysisGuaranteeRate).
  • Swagger e docstrings: os decorators acima, as descrições do router de parâmetros que citam a faixa única (apps/api/app/api/v1/routers/tenant_settings.py:38 e :119), a seção da taxa negociada em apps/api/app/main.py:316-317 e a linha de apps/api/app/main.py:374; o CLAUDE.md da API, seções TenantSettings e Negotiated Rate on Analysis Approval, que descrevem os campos antigos.
  • Testes (em apps/api/tests/):
  • test_tenant_settings_taxa.py — reescrito para os seis campos: RN2 (estado resultante, inclusive PATCH parcial que quebra a faixa), RN3 (null → 422), RN4 (onboarding).
  • test_mensalidade_por_tipo.py (novo) — RN6 (PF, PJ, sem principal), RN7 (dentro, fora, omitido grava sugerida), RN9 (cada pré-condição com seu código), RN10 (sequência emitir-depois-alterar → 409), RN11/RN12 (aprovada antes da spec emite com a sugerida do tipo; faixa alterada depois da decisão não muda a emissão), RN13, RN15, RN16 (campos, within_current_range, locked).
  • Negativos de autorização no mesmo arquivo: OPERATOR e VIEWER 403 no PATCH novo; AGENCY_USER 403; ANALYST de outro tenant 404; ADMIN_GLOBAL 403 PLATFORM_ADMIN_CANNOT_PRICE; AGENCY_USER não recebe set_by_name; ADMIN_GLOBAL não recebe a faixa.
  • Os testes existentes que gravam guarantee_rate_percent em TenantSettings (os arquivos que o grep acha em apps/api/tests/, entre eles conftest.py, test_emissao_de_garantia.py e test_upfront_payment.py) passam a gravar os campos novos.
  • rbac_seed.py: sem mudança.

apps/web

  • Páginas/componentes:
  • apps/web/src/pages/settings/index.tsx — os dois FormPanel de index.tsx:953 e :1001 viram um, "Mensalidade e atraso", com os três grupos da Parte II; FormState, EMPTY_FORM, a carga, o body do salvar e o conjunto CAMPOS_DO_FORMULARIO trocam os três campos pelos seis; os textos de ajuda das chaves guaranteeRate/minGuaranteeRate/maxGuaranteeRate são reescritos (hoje falam de "negociações com imobiliárias", que não é o que a faixa faz).
  • apps/web/src/pages/credit-analyses/components/DecisionPanel.tsx — o campo Mensalidade (%) no modo de edição; no modo leitura, a linha "Mensalidade aprovada" substitui a "Taxa aprovada" (DecisionPanel.tsx:331-336), com Alterar, edição, Salvar/Cancelar, avisos de faixa e de garantia emitida.
  • apps/web/src/pages/credit-analyses/show.tsx — estado do percentual ao lado do setupFee, envio na aprovação (handleApprove), linha "Mensalidade" no resumo do ApproveDialog, bloqueio da confirmação fora da faixa, e o resumo financeiro alimentado pelo guarantee_rate.
  • apps/web/src/pages/credit-analyses/components/ApproveDialog.tsx — só recebe a linha nova no resumo e o motivo de bloqueio; sem mudança de estrutura.
  • apps/web/src/pages/credit-analyses/components/FinancialSummaryPanel.tsx — a mensalidade, o total da vigência e o primeiro mês saem do guarantee_rate quando ele vem (e da prévia durante a edição), em vez de settings.guarantee_rate_percent (FinancialSummaryPanel.tsx:158).
  • apps/web/src/pages/credit-analyses/components/GuaranteeCreateDialog.tsx — os dois Dado de hoje, "Taxa" (GuaranteeCreateDialog.tsx:393, guarantee-create-taxa) e "Mensalidade" (:394, guarantee-create-mensalidade), viram um só: "Mensalidade" com "10,5% · R$ 315,00", no testId guarantee-create-mensalidade; o Dado de :393 sai. Abaixo dele, a frase por papel da Parte II (guarantee-create-mensalidade-hint).
  • apps/web/src/pages/credit-analyses/api.ts — tipo CreditAnalysisGuaranteeRate, campo no CreditAnalysis, approveAnalysis com o percentual, changeGuaranteeRate novo.
  • apps/web/src/pages/credit-analyses/mensalidade.ts (novo) — a prévia (RN17) e a checagem de faixa, puras, para teste unitário.
  • data-testid novos: settings-pf-guarantee-rate-input, settings-pf-min-guarantee-rate-input, settings-pf-max-guarantee-rate-input, settings-pj-guarantee-rate-input, settings-pj-min-guarantee-rate-input, settings-pj-max-guarantee-rate-input; decision-guarantee-rate-input, decision-guarantee-rate-preview, decision-guarantee-rate-read, decision-guarantee-rate-change-button, decision-guarantee-rate-save-button, decision-guarantee-rate-cancel-button, decision-guarantee-rate-warning, guarantee-create-mensalidade-hint. Saem settings-guarantee-rate-input, settings-min-guarantee-rate-input, settings-max-guarantee-rate-input e guarantee-create-taxa; o guarantee-create-mensalidade permanece, agora com "% · R$".
  • Sider / menu / rota: sem mudança — nenhum módulo novo.
  • Botão por permissão: Alterar aparece com decisions:update e credit_analyses:approve, fora do ADMIN_GLOBAL, com a análise APPROVED e guarantee_rate.locked === false. Esconder não protege — quem protege é a 10.2.
  • Responsividade & PWA: como a 7.1/7.2 — grid xs: 12, sm: 4 nos grupos de mensalidade dos Parâmetros; no painel do parecer, Alterar à direita da linha em sm+ e abaixo, largura inteira, minHeight: 44 em xs; inputMode: "decimal" nos campos. PWA: sem impacto além do bundle novo.
  • Testes unitários: apps/web/src/pages/settings/index.test.tsx (os seis campos e o erro por campo vindo do 422), apps/web/src/pages/credit-analyses/show.test.tsx (aprovação envia o percentual; confirmação bloqueada fora da faixa; Alterar só com as permissões e sem garantia), apps/web/src/pages/credit-analyses/mensalidade.test.ts (novo — arredondamento meio para cima e faixa), apps/web/src/pages/credit-analyses/components/GuaranteeCreateDialog.test.tsx (a frase por papel).

apps/e2e

  • Specs:
  • apps/e2e/tests/e2e/mensalidade-por-tipo.spec.ts (novo): Parâmetros com os seis campos e erro de faixa; aprovar uma análise de tomador PF mudando o percentual e vendo a prévia; Alterar depois de aprovada; emitir e conferir que a garantia sai com o percentual escolhido e que o Alterar some; o mesmo caminho em 375px conferindo scrollWidth - clientWidth == 0 e o Alterar de largura inteira. Restaura os parâmetros no finally (lição da spec 0025: parâmetro do tenant é compartilhado).
  • apps/e2e/tests/e2e/settings-mobile-snackbar.spec.ts — troca settings-guarantee-rate-input (linhas 40 e 61) pelo settings-pf-guarantee-rate-input.
  • apps/e2e/tests/e2e/emissao-de-garantia-na-analise.spec.ts — a asserção de guarantee-create-taxa (linha 242) sai, e a de guarantee-create-mensalidade (linha 243) passa a casar um número antes de % e R$ (a mesma guarda contra undefined% que o comentário da linha 241 explica).
  • Seeds: o seed_e2e.py cria os parâmetros pelo _default_settings (apps/api/app/db/seed_e2e.py:237 e :309), então a garantidora do e2e recebe os valores da RN4 pela mudança no onboarding (e, num banco já semeado, pela migração). Nenhuma mudança no seed. Uma análise de tomador PJ, se o spec precisar, é criada pelo próprio spec.

12. Contrato de API

Parâmetros

PATCH /api/v1/settings
Authorization: Bearer <token de ADMIN_TENANT>

{ "pf_guarantee_rate_percent": "9.50", "pf_min_guarantee_rate_percent": "8.00",
  "pf_max_guarantee_rate_percent": "11.00", "pj_guarantee_rate_percent": "16.00",
  "pj_min_guarantee_rate_percent": "15.00", "pj_max_guarantee_rate_percent": "18.00" }

Resposta: o TenantSettingsResponse com os seis campos e sem os três antigos. Erros: 422 GUARANTEE_RATE_RANGE_INVALID (RN2), 422 FIELD_REQUIRED (RN3), 422 VALIDATION_ERROR (fora de 0,01–100), 403 para quem não é ADMIN_TENANT.

Aprovar

POST /api/v1/credit-analyses/{id}/decision/approve

{ "opinion": "…", "approved_initial_fee_value": "300.00",
  "approved_guarantee_rate_percent": "9.50" }

Resposta: AnalysisResponse, agora com approved_guarantee_rate_percent sempre preenchido e guarantee_rate_set_at. Erros novos ou mudados: 422 RATE_OUT_OF_RANGE com a faixa do tipo. Os demais, inalterados.

Alterar

PATCH /api/v1/credit-analyses/{id}/decision/guarantee-rate
Authorization: Bearer <token>

{ "guarantee_rate_percent": "10.50" }
{ "id": "uuid-da-decisao", "status": "APPROVED",
  "approved_guarantee_rate_percent": "10.50",
  "guarantee_rate_set_at": "2026-10-12T14:32:00Z", "...": "demais campos do AnalysisResponse" }

Permissão: decisions:update e credit_analyses:approve. Erros: 404 NOT_FOUND (outro tenant, outra imobiliária, inexistente), 403 (sem as permissões), 403 PLATFORM_ADMIN_CANNOT_PRICE (ADMIN_GLOBAL), 422 ANALYSIS_NOT_APPROVED, 409 GUARANTEE_EXISTS, 422 RATE_OUT_OF_RANGE, 422 VALIDATION_ERROR (fora de 0,01–100 ou ausente).

Leitura

GET /api/v1/credit-analyses/{id} ganha:

"guarantee_rate": {
  "renter_type": "PF",
  "suggested_percent": "8.00", "min_percent": "8.00", "max_percent": "11.00",
  "approved_percent": "9.50",
  "effective_percent": "9.50", "source": "APPROVED",
  "monthly_value": "285.00",
  "within_current_range": true,
  "set_by_name": "Fulana", "set_at": "2026-10-12T14:32:00Z",
  "locked": false
}

null só quando o tenant não tem TenantSettings (o mesmo caso em que o initial_fee fica sem regra). Recortes por papel na 10.1/10.4.

Migration — <rev>_mensalidade_por_tipo_de_tomador

  • upgrade: acrescenta os seis campos em tenant_settings, primeiro anuláveis; grava em todas as linhas os valores da RN4; torna-os NOT NULL; remove guarantee_rate_percent, min_guarantee_rate_percent e max_guarantee_rate_percent. Acrescenta guarantee_rate_set_by_id (FK users.id, SET NULL) e guarantee_rate_set_at em decisions, anuláveis, sem preencher — decisões antigas não sabem quem fixou a taxa, e a tela mostra a linha sem o "Alterada por". Não toca decisions.approved_guarantee_rate_percent nem guarantees.
  • downgrade: recria os três campos antigos, anuláveis; preenche guarantee_rate_percent, min_ e max_ com os valores PF de cada linha (a PF é a que mais se aproxima da taxa única de antes); torna-os NOT NULL; remove os seis novos e as duas colunas de decisions. O que o downgrade não devolve: os valores antigos de taxa padrão, mínima e máxima de cada garantidora — a RN4 os substitui por decisão do usuário, e não há onde guardá-los. Isso é dito aqui para não ser surpresa: voltar a versão deixa a taxa única com o valor PF.
  • Produção: a TXC passa a ter PF 8–11 (sugerida 8) e PJ 15–18 (sugerida 15). O /ship faz backup antes de migrar.

13. Critérios de aceite

  • [x] CA1 (RN1, RN4). Depois da migração, toda linha de tenant_settings tem PF 8/8/11 e PJ 15/15/18, e os três campos antigos não existem; uma garantidora criada pelo onboarding nasce com os mesmos valores.
  • [x] CA2 (RN2). PATCH /settings com pf_min_guarantee_rate_percent=12 sobre PF 8/8/11 responde 422 GUARANTEE_RATE_RANGE_INVALID com details[0].field igual a pf_min_guarantee_rate_percent, e nada muda no banco; com pj_guarantee_rate_percent=14 sobre PJ 15/15/18, o campo apontado é pj_guarantee_rate_percent.
  • [x] CA3 (RN3). PATCH /settings com pj_max_guarantee_rate_percent: null responde 422 FIELD_REQUIRED.
  • [x] CA4 (RN5). Multa e juros continuam salvando e valendo como na spec 0054 (os testes existentes dessa spec seguem verdes).
  • [x] CA5 (RN6, RN7). Aprovar análise de tomador PJ informando 16% grava 16%; informando 12% responde 422 RATE_OUT_OF_RANGE com "pessoa jurídica" e "15% a 18%" na mensagem; omitindo, grava 15% (a sugerida PJ). Numa garantidora sem TenantSettings, aprovar responde 422 SETTINGS_NOT_FOUND e a decisão não muda.
  • [x] CA6 (RN6). Numa análise com locatário principal PF e corresponsável PJ, a faixa aplicada é a de PF.
  • [x] CA7 (RN8, RN9). O ANALYST altera a taxa de uma análise aprovada sem garantia de 9,5% para 10,5%: 200, guarantee_rate_set_by_id é ele, guarantee_rate_set_at é o instante, e há um AuditLog GUARANTEE_RATE_CHANGED com from 9.50 e to 10.50.
  • [x] CA8 (RN9, RN10). Emitida a garantia, o mesmo PATCH responde 409 GUARANTEE_EXISTS e a taxa da decisão e da garantia não mudam.
  • [x] CA9 (RN9). PATCH em análise IN_ANALYSIS responde 422 ANALYSIS_NOT_APPROVED; PATCH com 12% numa PF responde 422 RATE_OUT_OF_RANGE.
  • [x] CA10 (RN11, RN12). Uma análise aprovada antes da migração (decisão sem taxa) e de tomador PJ emite garantia com guarantee_rate_percent 15 e todas as parcelas mensais com amount igual ao monthly_value calculado a 15%.
  • [x] CA11 (RN12). Aprovada a 9% (PF), a garantidora muda a faixa PF para 10–12; a emissão sai a 9%, e o guarantee_rate.within_current_range da análise era false antes de emitir.
  • [x] CA12 (RN13). A simulação com análise aprovada a 10,5% devolve guarantee_rate_percent 10.5 e o mesmo monthly_value que a emissão grava.
  • [x] CA13 (RN15). Depois da alteração do CA7, o financial_summary da análise mostra guarantee_rate_percent 10.5 e monthly_value = Pacote × 10,5%; o LMI do snapshot não muda.
  • [x] CA14 (RN16). O GET da análise do CA7 traz guarantee_rate com renter_type, a faixa, approved_percent 10.5, source APPROVED, monthly_value, set_by_name e locked false; depois da emissão, locked true.
  • [x] CA15 (10.1, negativo OPERATOR). O OPERATOR recebe 403 no PATCH novo, e na tela não vê o Alterar; vê, no diálogo de emissão, a frase "Definida pela garantidora na aprovação…".
  • [x] CA16 (10.1, negativo VIEWER). O VIEWER recebe 403 no PATCH novo.
  • [x] CA17 (10.1/10.4, negativo imobiliária). O AGENCY_USER recebe 403 no PATCH novo; no GET da análise da própria imobiliária recebe guarantee_rate com effective_percent e monthly_value, e set_by_name/set_at nulos; no GET da análise de outra imobiliária, 404.
  • [x] CA18 (10.3, negativo tenant). O ANALYST do tenant B recebe 404 no PATCH sobre análise do tenant A, e a taxa não muda.
  • [x] CA19 (10.5, negativo ADMIN_GLOBAL). O ADMIN_GLOBAL recebe 403 PLATFORM_ADMIN_CANNOT_PRICE no PATCH novo, tanto para análise existente quanto para um id inexistente; no GET da análise, guarantee_rate vem com suggested_percent, min_percent e max_percent nulos.
  • [x] CA20 (Parte II, Momento A). Nos Parâmetros há um só bloco "Mensalidade e atraso", com os grupos PF, PJ e Atraso; o erro de faixa aparece debaixo do campo errado; em 375px os campos empilham sem rolagem horizontal.
  • [x] CA21 (Parte II, Momento B, RN17). No painel do parecer, o campo Mensalidade vem com a sugerida do tipo; digitar 9,5 numa análise de Pacote R$ 3.000 mostra "R$ 285,00 por mês" sem nenhuma requisição; 12 numa PF mostra o erro e desabilita o confirmar da aprovação; a confirmação traz a linha "Mensalidade".
  • [x] CA22 (Parte II, Momento C). Aprovada e sem garantia, quem pode aprovar vê "Mensalidade aprovada" com Alterar, edita, vê a prévia, salva e vê "Alterada por …"; em 375px o Alterar fica abaixo da linha, largura inteira, 44px de altura; emitida a garantia, o Alterar some e aparece o texto de garantia emitida.
  • [x] CA23 (Parte II, 7.3). O aviso "Fora da faixa atual…" aparece quando within_current_range é false; sem parâmetros, o campo e a confirmação dizem isso e a confirmação trava; o 409 ao salvar mostra a mensagem de garantia emitida e volta ao modo leitura. (Revisto na implementação — ver Registro: não há leitura da faixa à parte que possa falhar sozinha.)

14. Plano de implementação

Ordem obrigatória no monorepo: api → web → e2e.

  • [x] apps/api — domain/mensalidade.py com testes puros (RN6, RN11)
  • [x] apps/api — models e migration (RN1, RN4, RN8), com downgrade exercitado no dev-remote
  • [x] apps/api — settings: schema e service (RN2, RN3), onboarding (RN4)
  • [x] apps/api — decisão: aprovar (RN7, RN8, RN15), alterar (RN9, RN10), guarda do ADMIN_GLOBAL (10.5)
  • [x] apps/api — emissão e simulação (RN10, RN12, RN13); resposta da análise (RN16)
  • [x] apps/api — docstrings, Swagger, main.py, CLAUDE.md da API
  • [x] apps/api — testes (seção 11), primeiro vermelhos
  • [x] apps/web — Parâmetros, painel do parecer, aprovação, resumo financeiro, diálogo de emissão, com data-testid e os dois viewports; testes unitários
  • [x] apps/e2e — spec novo e os dois ajustes
  • [x] make test, make lint (sem apontamento novo nos arquivos tocados)
  • [x] Validado no dev-remote em desktop e 375px

15. Decisões em aberto

Nenhuma. As decisões tomadas pelo usuário em 2026-10-12, para referência: painel único "Mensalidade e atraso" com sugerida/mínima/máxima por tipo; o tomador decide o tipo; altera quem pode aprovar; análises aprovadas e sem garantia passam a usar a política nova; a imobiliária vê a mensalidade escolhida; valores de partida PF 8–11 e PJ 15–18 com sugerida no mínimo; o ADMIN_GLOBAL não altera a taxa.

16. Revisão do detalhamento

Preenchido pelo laço do /spec new, rubrica .claude/rubrics/detalhamento.md.

Rodada Critical Important Minor Nota Veredicto
1 0 0 7 8,5 Aprovada

Resultado: aprovada na rodada 1.

Pendências aceitas: nenhuma. Os sete Minor foram corrigidos no texto depois da aprovação: a terceira leitura de settings.guarantee_rate_percent no _origem_da_taxa e as descrições do router de parâmetros entraram no impacto; a RN10 passou a exigir populate_existing na leitura travada; a RN2 passou a dizer qual campo o details aponta; o diálogo de emissão funde "Taxa" e "Mensalidade" numa linha só; a RN7 recusa aprovar sem TenantSettings; a guarda do ADMIN_GLOBAL vem antes de resolver a análise (RN9, passo 0); e três citações foram acertadas.

17. Revisão da implementação

Preenchido pelo /spec implement, rubrica .claude/rubrics/implementacao.md. As revisões de fase (api, web, e2e) vão nas primeiras linhas; a da branch inteira, na última.

Rodada Escopo Critical Important Minor Nota Veredicto
1 apps/api 0 1 6 8 Aprovada
2 apps/web 0 2 6 7 Reprovada
3 apps/web 0 3 4 7 Reprovada
4 apps/web 0 1 5 8 Aprovada
5 apps/e2e 0 1 4 7 Reprovada
6 apps/e2e 0 1 5 8 Aprovada
7 branch 0 0 4 8,5 Aprovada

Resultado: aprovada na rodada 1 da revisão de branch (rodada 7 da tabela).

Defeitos aceitos:

  • change_guarantee_rate reescreve o recorte de tenant e imobiliária em vez de usar app/services/scoping.py — não usa o _get_decision porque análise sem parecer deve dar 422, não 404. Está correto e testado (404 por tenant e por imobiliária), mas é uma segunda cópia da regra de escopo. Fica para quem mexer em scoping.py.
  • Os Minors das revisões de fase que a revisão da branch triou como "pode ficar": a frase por papel do diálogo de emissão testada no componente e não na página; a sugerida PJ do resumo do formulário sem teste próprio; no e2e, o mesmo usuário aprova e altera, a sugerida e a mínima PF coincidem no tenant compartilhado, e o diálogo de emissão não é exercitado com o percentual escolhido — cada um com cobertura em outra camada (pytest ou unitário do web).

18. Registro

O que divergiu do planejado na implementação, e por quê:

  • CA6 testado com segundo locatário PJ, não com corresponsável PJ. Corresponsável PJ é proibido desde a spec 0003 (CO_RESPONSIBLE_MUST_BE_PF); o que a regra quer provar — só o tomador decide a faixa — é o mesmo com um locatário PJ não principal.
  • get_lessee_types no repositório de participantes. A seção 11 dizia "sem mudança"; a leitura do tipo do tomador precisava do join com Renter, e get_lessees devolve só o participante. Mesma ordem, principal primeiro.
  • test_tenant_settings_taxa.py não foi reescrito — ele testa a regra de adesão da spec 0056, não a mensalidade. RN1–RN4 estão em test_mensalidade_por_tipo.py.
  • _origem_da_taxa recebe a sugerida PF, não a taxa em vigor. A taxa ali só alimenta o cálculo de que se aproveita o .initial_fee, que não depende dela; buscar a taxa em vigor custaria duas consultas por leitura sem mudar o resultado.
  • Testes de aprovação existentes ganharam TenantSettings. Treze testes aprovavam numa garantidora sem parâmetros e passaram a receber 422 SETTINGS_NOT_FOUND (RN7). O de emissão sem parâmetros passou a criá-los para aprovar e apagá-los antes de emitir — é o cenário que ele guarda.
  • Com garantia emitida, a taxa em vigor é a da garantia (RN16 ampliada). Achado da revisão da fase web: a RN16 não dizia o que mostrar numa análise com garantia emitida e decisão sem taxa (todas as de antes da spec), e a tela mostrava a sugerida nova ao lado de "não muda mais". A resposta sai da RN14 — garantia emitida não muda — e não é decisão nova.
  • "Definida por", não "Alterada por". A aprovação também grava quem fixou a taxa (RN8); numa análise só aprovada, "Alterada por" diria que alguém alterou o que só aprovou.
  • Os estados "faixa carregando" e "faixa não carregou, Tentar novamente" da 7.3 não existem. A faixa vem dentro da análise (RN16), não numa leitura à parte: enquanto a análise carrega a página inteira é esqueleto, e se a leitura da análise falha a página mostra o erro dela, como já fazia antes desta spec — não há uma segunda leitura que possa falhar sozinha. O que sobra é guarantee_rate nulo, que significa garantidora sem TenantSettings: o campo diz "A garantidora ainda não configurou a mensalidade nos Parâmetros.", fica desabilitado, e a confirmação de aprovação trava com a mesma frase, porque a aprovação seria recusada (RN7). Sem parâmetros e com taxa já decidida, o parecer mostra a taxa decidida numa linha simples, para o dado gravado não sumir.
  • O SaaS admin não recebe o campo na aprovação. Ele aprova como hoje, mas não recebe a faixa (10.5); sem ela o campo seria um "carregando" eterno. A aprovação dele grava a sugerida, e a confirmação diz isso.
  • CreditAnalysisForm.tsx entrou no impacto. O resumo do formulário lia a taxa padrão, que deixou de existir; passou a receber a sugerida do tipo do inquilino principal.
  • A linha da mensalidade da emissão é o componente MensalidadeNaEmissao, testado direto: o preço só aparece com a vigência preenchida, e o seletor de data não se preenche no jsdom. O fluxo com datas fica no e2e.
  • O e2e dos Parâmetros não tem finally de restauração. A seção 11 o previa; o spec não grava parâmetro nenhum — só provoca a recusa de faixa (RN2), que não grava. O risco que sobra é a RN2 regredir e a recusa virar gravação: aí o teste falha na asserção que relê a faixa pela API, e a faixa quebrada fica no tenant compartilhado até alguém salvar de novo.
  • locked usa a mesma régua da escrita. Achado da revisão da branch: a leitura ignorava garantia removida em soft delete (spec 0049) e a escrita não, e a tela oferecia um Alterar que sempre recebia 409. Agora garantia removida também trava a taxa — ela pode ser restaurada com a taxa congelada.
  • videos/preparar-ambiente.mjs entrou no impacto. O script do ambiente de demonstração dos tutoriais mandava os três campos antigos; passou a mandar os seis.
  • A imobiliária não emite garantia (sem guarantees:create): quem emite sem poder aprovar é o operador, e a frase "fale com a garantidora" é para ele.

Afirmações conferidas

Fatos sobre o repositório que uma rodada de portão já conferiu abrindo o arquivo. O recortar.py leva esta seção junto em qualquer parte, e o revisor da rodada seguinte pode tomá-los como dados em vez de reconferir tudo do zero.

Afirmação Onde na spec Conferida em

Duas regras, e a segunda é a que faz a primeira valer:

  1. Só entra o que um revisor conferiu — não o que você conferiu ao escrever. O ponto é aproveitar trabalho já pago por uma rodada, não abrir atalho para afirmar sem prova.
  2. Mexeu na frase da spec, a linha sai da tabela. A afirmação volta a ser conferível. Sem isso a tabela vira o oposto do portão: uma afirmação carimbada como verdadeira porque um dia foi.

Feature sem afirmação sobre o repositório não precisa da seção — apague-a.