A corrente do cliente: do extrato à meta travada, e o mês que agora fecha - #59
Merged
Conversation
…ticos que sustentam os números Três frentes: o cenário macro do Brasil (fontes primárias, corte 17/ago), o que o ATR OS de fato faz (verificado no código com arquivo:linha) e a oferta de valor que liga os dois — mais o pente fino da jornada de um cliente simulado. Os cinco scripts diag-* são READ-ONLY e produziram os números da E2. O diag-grupos-por-transacao também serve como ferramenta comercial: roda no primeiro extrato e estima o esforço de onboarding ANTES de fechar contrato. Achados medidos que mudaram conclusões: - linhas/grupo varia 6,6x entre clientes reais (Vertimetal B2B 29,8 x Prudente B2C com PIX nominal 4,5) — o custo de categorização é função do MODELO DE NEGOCIO do cliente, não do volume de transações; - a cauda é cardinalidade real, não bug de normalização (prefixo colapsa só 10%); - 311 decisões cobrem 80% das linhas; as 1.497 seguintes cobrem os 20% restantes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… contraparte no histórico
O detector de partes relacionadas era bom e estava desligado da tomada: a tabela
que ele lê (client_socios) NÃO tinha escritor nenhum no código — as 8 linhas
existentes foram inseridas à mão por SQL. E o detector só rodava em
confirmarImportacao, então cadastro novo nunca alcançava o histórico já
importado. Medido antes: 16 de 18.097 transações com contraparte marcada.
socios-do-qsa.ts (puro): extrai sócios PF de companies.dados_receita.qsa,
converte a máscara da Receita (***939098** -> 939098) para o CHECK de 6 dígitos,
ignora sócio PJ (é empresa_grupo, não client_socios) e inclui o representante
legal, que era descartado. Empresa cadastrada à mão (sem enriquecimento) degrada
para nome só, com confiança média.
sincronizar-socios.ts: upsert idempotente pelo índice único (client_id, upper(nome)).
Sócio de fonte 'manual' NUNCA é sobrescrito — o comentário da tabela no banco diz
que sócio de fato não registrado é comum em PME, e é justamente esse caso.
varredura-contraparte.ts: espelha aplicarRegrasNoProjeto. Só toca linhas com
contraparte_tipo IS NULL e grava alta e média — o schema previu as duas
(CHECK IN ('alta','media')) e o gate JÁ renderiza média como "identificada pelo
nome, confira". Persistir média não decide nada: nada age sem contraparte_porta,
que é escolha do dono. E é o que torna eficaz a trava da regra por token.
O sync fica em CompanyService.criar/atualizar, condicionado a dados_receita no
payload: são QUATRO telas que enriquecem empresa e todas afunilam ali. No caminho
de leitura não dava — a policy client_socios_insert exige consultor+, e o leitor
também roda na ingestão feita pelo cliente.
Aplicado em dado real: contraparte socio 5 -> 795, empresa_grupo 9 -> 193,
propria 2 -> 57. Os 795 batem exatamente com a medição manual que o autor do
detector deixou no cabeçalho do arquivo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
As 49 regras genéricas da casa são REGEX; as regras que o CLIENTE cria eram só
igualdade exata. O sistema sabia casar por padrão, mas só para si mesmo.
Medido em produção: PRUDENTE & SILVA tem 1.358 grupos de uma ocorrência (75% das
decisões, 17% das linhas), e 1.157 deles (85%) contêm o token MAQUININHA com 100%
de pureza de sentido — 1.157 clientes diferentes pagando pelo MESMO canal, todos
venda no balcão. Prefixo não resolve (4%): o nome da pessoa vem primeiro.
Com token, 1.808 decisões caem para ~529.
match_type ('exact' | 'contains') com DEFAULT 'exact' — as 151 regras existentes
seguem casando por igualdade, byte a byte. Verificado no banco após a migration.
filtroDeRegra() é fonte única dos três pontos de aplicação (importação, varredura
e lote da tela), e carrega A TRAVA: regra 'contains' só toca linha SEM contraparte
detectada. Sem isso, uma regra ampla em entradas varreria aporte de sócio para
dentro da receita e contaminaria margem, ponto de equilíbrio e a meta do Plano de
Voo — são 1.029 lançamentos protegidos por essa cláusula hoje.
escaparParaIlike() fecha o outro furo: '%' e '_' no pattern do cliente virariam
curinga e a regra pegaria mais do que ele viu no preview.
Precedência exact -> contains resolvida no sort em TS: depender da ordenação
alfabética do Postgres ('contains' < 'exact') seria acidente, não desenho.
O preview é obrigatório e mostra o que protege: "1.157 lançamentos, R$ 134.012,
todos entrada — e 900 movimentações de sócio que eu não vou tocar".
MatchType já existia declarado com 'starts_with' e 'regex' e nunca fora usado.
Os dois saíram: starts_with foi MEDIDO e cobre 4%; regex vindo do usuário é ReDoS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…rio projeto Decisão do Lucas (18/ago): o ATR OS é SaaS de uso próprio. Todo o sistema é do cliente; dentro de um projeto quem manda é ele — contrata, cadastra a própria empresa e sócios, categoriza, fecha o mês e trava a própria meta. O consultor deixa de ser etapa: é ferramenta externa opcional, só enxerga se o cliente ligar, e sem nenhuma limitação diferente da do cliente. Owner/admin veem todos. Isso INVERTE a hierarquia atual (owner > admin > consultor > cliente, onde o consultor tem mais poder que o cliente no projeto): a autoridade passa a vir de posse do projeto, não de degrau. Levantado contra a RLS: as perguntas 1 a 5 da cadeia o cliente já faz sozinho, mas 6 e 7 — "pra onde eu vou" e "o que eu faço" — estão trancadas em canOperateProject e no gate de Iniciativas. Raio medido: 104 das 348 policies codificam o bypass de 3 papéis, em 47 tabelas. A boa notícia é que project_members (com granted_by) JÁ é o mecanismo que o modelo pede — a execução é repoint, não invenção. A pegadinha: a view client_project_access filtra role='cliente' e 242 policies a consomem, então do jeito que está ela exclui o consultor de tudo. Fica decidida e NÃO executada — próxima sessão. Uma pergunta aberta registrada no doc: consultor lê ou também escreve (muda de 1 para 2 policies por tabela). ESTRUTURA.md regerado: client_socios 1 -> 4 usos, transactions 77 -> 81, companies 24 -> 25. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…aaS obriga a reler A decisão de que o ATR OS é SaaS sem consultor chegou no FIM da sessão. F2, F3 e o pente fino foram escritos com o consultor como premissa silenciosa: não estão errados nos fatos (tudo verificado no código), mas estão errados no julgamento — toleravam como normal um passo que agora não tem dono. O handoff registra item por item o que precisa ser relido (F1 não muda; F2 §5.3 e §7, F3 §6 e §8, E1 e E2 mudam) e a consequência mais dura: sob SaaS, as 4 a 29 horas de categorização da E2 são INTEIRAMENTE do cliente, sozinho, antes de ver qualquer valor. Isso promove a regra por token de otimização a existencial. E levanta a pergunta que a trilha nunca fez porque havia um consultor implícito para traduzir: o cliente sozinho consegue INTERPRETAR o que vê? Nas etapas E4-E6 esse vira o critério principal. Inclui: as 9 etapas com estado, o que já foi aplicado em produção (migration + varredura de contraparte em dado real), o aviso de que o db/snapshot está atrás do banco, as 2 perguntas que travam trabalho, e os gotchas de build/lint descobertos na marra (o build type-checa scripts/; o hook de commit precisa de mais de 2 min). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…stava quebrado Os três scripts de diagnóstico da leva de regra por token anotam o callback do `.find()` com um tipo `ProjetoRef` que nunca foi declarado em lugar nenhum. Estão commitados desde a sessão anterior, e como o `npm run build` type-checa `scripts/` junto com `src/`, a branch não compilava. Declarado em cada arquivo, no mesmo formato que o irmão que já compilava (`diag-grupos-por-transacao.ts` faz o cast inline equivalente). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…o próprio projeto Executa a lei `docs/atros-v3/saas-sem-consultor.md` (decisão de 18/ago). As três migrations já estão APLICADAS em produção; o snapshot foi re-dumpado e confere. O que inverte ------------- `canOperateProject` deixa de exigir `PROJECT_OPERATOR_ROLES` e passa a exigir VÍNCULO: membro do projeto opera, owner/admin operam qualquer um. A linha `// cliente/sdr nunca operam` morreu. Ler e escrever passaram a ter a mesma regra de autorização, então a função delega para `canAccessProject`. O que a lei não tinha mapeado ----------------------------- Ela descreve 3 padrões de bypass; existem 5. O que faltava — 36 policies em 22 tabelas fixando `pm.role = 'consultor'` — é invisível ao grep dela e era justamente o que tornaria a inversão INERTE: o dono passaria no app e apanharia da RLS, em silêncio. Números corrigidos: 367 policies (não 348), 120 bypasses (não 104), 97 policies a repointar (não 242 — a doc contou linhas). O gate de qualidade estava fora do caminho de escrita ----------------------------------------------------- `planoVooDestravado` (12 meses da janela fechados) só existia no render de `page.tsx`. As actions e a rota aceitavam qualquer chamada. Enquanto o cliente não operava isso não vazava; no minuto da inversão viraria meta calibrada em dado ruim. Agora está em `generate` e em `approve`. As migrations ------------- 20260818010000 os 2 INSERTs do caminho de escrita do Plano de Voo 20260818020000 view `project_access` + 139 policies reescritas 20260818030000 o dono cadastra e conserta o próprio cadastro Decisões travadas: consultor escreve igual ao cliente (1 policy por tabela); DELETE de dado financeiro apurado segue admin-only, cadastro abre pro dono. Ferramental em `scripts/saas/` (read-only) ------------------------------------------ 139 policies não se escreve à mão. `transformar-policies.ts` divide a expressão booleana em disjuntos de topo e remove só o certo, provando balanceamento de parênteses; `auditar-acesso-do-dono.ts` é o gate (dono bloqueado 177 → 142, 37 destravadas, zero regressões); `verificar-dump.ts` confere contra o dump, não contra a migration. Nota: `plano-voo/actions.ts` também perde aqui a limpeza morta de `cockpit_actions` — o conserto do Cockpit vem no commit seguinte. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…m por estar logado
Achado ao mapear o terreno do SaaS, não estava em lista nenhuma. Já APLICADO em
produção; o snapshot foi re-dumpado e confere.
O problema
----------
31 policies RLS liberavam acesso por simplesmente ESTAR LOGADO
(`auth.role() = 'authenticated'`, `USING (true)`). Como policies permissivas se
somam por OR, elas anulavam todo o escopo por vínculo das vizinhas: não adianta
a policy do lado exigir `project_members` se a outra libera geral.
Sob o modelo antigo — só a equipe da ATR tinha login — era desleixo contido. Com
o signup self-service em produção, é vazamento entre clientes:
· `projects` SELECT+UPDATE+INSERT: qualquer cliente logado listava TODOS os
projetos da plataforma e dava UPDATE em qualquer um — inclusive no
`data_inicio`, que define a janela de 12 meses da meta
· `profiles` USING (true): nome, e-mail e papel de todo mundo
· `categorization_rules` / `learned_rules` ALL: a inteligência de
categorização de um cliente legível E gravável por outro
· `activity_log` INSERT WITH CHECK (true), sem nenhum inserter no código —
servia só pra forjar log em nome de outro
· `class_access` idem: auto-concessão de acesso a curso
Resultado: 31 → 8. As 8 que ficam são SELECT em catálogo global sem chave de
tenant (`dre_categories`, `financial_benchmarks`, `class_*`, `library_content`,
`subcategories`, `categorization_patterns`) — desenho correto, não vazamento.
A armadilha do subselect
------------------------
`project_members` tem RLS own-row (`project_members_self`): subselect nela dentro
de policy roda como o usuário, então procurar o vínculo de OUTRA pessoa volta
vazio SEM ERRO. A policy de `profiles` precisa enxergar o colega de projeto — por
isso usa a view `project_access`, que roda como owner e atravessa. Escrita com a
tabela, passaria no review e negaria tudo em silêncio.
Regra que fica: precisa ver vínculo de terceiro ⇒ use a view, nunca a tabela.
Gate: `npx tsx scripts/saas/auditar-acesso-do-dono.ts --vazamento`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Bug latente de três camadas, achado ao ir escrever a policy de DELETE que falta
em `cockpit_actions`. A policy acabou não sendo o conserto.
1. A limpeza mirava o alvo errado
`approvePlanoVooV2Action` fazia `.delete().eq("snapshot_id", snapshotId)` — o
snapshot que está sendo aprovado AGORA, que nunca tem linha, porque re-aprovar
o mesmo snapshot é barrado antes. Código morto. E inerte de qualquer forma:
`cockpit_actions` não tem policy de DELETE, então o delete apagava zero linhas
sem erro.
2. O Cockpit não filtrava por plano
`api/projetos/[id]/cockpit` lia por `project_id`. Aprovar um segundo plano
arquiva o anterior mas não mexe nas ações dele ⇒ o dono veria 24 ações, metade
de um plano que já não vale.
3. A FK é ON DELETE SET NULL
Excluir planos deixa ações órfãs com `snapshot_id` nulo, para sempre.
O conserto é ler, não apagar
----------------------------
Nasce `plano-voo/snapshot-vigente.ts` — resolvedor único do snapshot aprovado
vigente, recebendo o client por parâmetro (o Cockpit usa o do usuário, o motor do
HTR usa o service client). O Cockpit filtra por ele. Preserva o histórico — as
ações antigas e o progresso marcado nelas continuam na tabela — e resolve as três
camadas sem policy nova.
Quarta camada, achada no caminho
--------------------------------
`pe35-auto-gen-service` resolvia o snapshot por `created_at` desc SEM filtrar
status (o comentário dizia "snapshot ativo"). Podia grudar a escalação do HTR num
rascunho, que o Cockpit — agora lendo por vigente — jamais mostraria. E
`getSemanaAtualDoPV` contava as ações do projeto inteiro, somando semanas de plano
arquivado para decidir a próxima.
`cockpit_actions` tem zero linhas em produção (conferido no seed.sql): o bug era
latente e o fix não tem risco de dado. Os 4 testes novos travam o FILTRO, que é o
que era o bug — se alguém tirar o `status='aprovado'` ou voltar a ordenar por
`created_at`, eles caem.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…r por IA
Os dois estavam rotulados como "baratos" no backlog. Nenhum era o que dizia.
G-05 — eram 8 lugares em 6 arquivos, não 2
-------------------------------------------
E três propagavam DECISÃO REVOGADA, não só número velho:
plano-voo-gate.ts:6 "≥3 snapshots mensais ATIVOS"
iniciativas-gate.ts (×2) "≥3 meses" + "o ato explícito do consultor"
useProjectSidebarBadges (×2) "≥3 meses" + "gate D-3"
Sidebar.tsx:145 "≥3 meses + folha"
htr-consultant-agent.ts:62 "≥3 snapshots + folha"
financial-snapshot-service:86 citava `learned_rules`, removida abaixo
Folha deixou de ser gate em 2026-06-05 (que é exatamente a revogação da D-3), e
sob o SaaS quem aprova o plano é o DONO, não o consultor. O gate real é 12 desde
2026-07-28, e por COBERTURA da janela, não por contagem.
A armadilha: dois candidatos óbvios estavam CERTOS
--------------------------------------------------
Um replace de "≥3 → 12" varrendo o repo teria corrompido dois comentários
corretos, que descrevem outra regra com um 3 real:
auto-conclusion-service.ts:91 é literalmente `snapshotsTotal >= 3`
module-service.ts:51 + dre-publishing-service.ts:6
rascunho (<3) → preliminar (3-11) → consolidada (12+)
Regra que fica: o número na prosa só é erro se o literal no código disser outra
coisa. Conferir o literal antes de trocar o texto.
G-08 — o categorizador por IA, e a cascata que ninguém tinha mapeado
--------------------------------------------------------------------
Decisão do Lucas (17/ago): a categorização do ATR OS é determinística, sem IA.
`ai-categorizer.ts` tinha zero callers — 210 linhas removidas.
Matar ele torna morto o `CATEGORY_MAP`, que existia só para alimentá-lo, o que
por sua vez mata `FINANCIAL_SUBCATEGORIES`, que existia só para montar o
`CATEGORY_MAP`. `constants/financial-categories.ts` foi de 123 para 25 linhas;
sobra `FINANCIAL_CATEGORIES`, com 9 consumidores vivos.
O DROP de `learned_rules` ficou para depois, por decisão do Lucas. A migration
NÃO fica em `supabase/migrations/`: migration não aplicada quebra o oráculo de
frescor (marca o dump como obsoleto sem ele estar) e um `supabase db push` a
aplicaria sem perguntar. O SQL, a prova de que é seguro e a cauda obrigatória
estão parqueados no G-08 do `docs/valor/gaps-backlog.md`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… como e o que falta
Re-dump
-------
Duas rodadas no dia, ambas com guarda de tamanho (dump em temporário, validação,
só então instalar — a lição do dump vazio que quase virou perda de dado).
Views 12 → 13 (`project_access`)
Policies 362 → 353
Tabelas · Funções · Triggers · Índices iguais
Os dois deltas foram PREVISTOS antes de rodar o dump e bateram exato: +1 view /
0 policies na leva do SaaS (146 pares DROP+CREATE com saldo zero — nada se
perdeu, nada duplicou), −9 policies na leva do vazamento. Prever o delta é o que
separa "a migration rodou" de "a migration fez o que eu quis".
Oráculo de frescor: AUTORITATIVO (`ultima_migration_incluida = 20260818050000`).
Gate contra a realidade: `npx tsx scripts/saas/verificar-dump.ts` — 0 policies na
view antiga, 108 na `project_access`, 0 policies abertas fora de catálogo global.
Ninguém foi trancado do lado de fora: a conferência de quem perderia o bypass por
papel global voltou VAZIA — não existe um único `profiles.role` em
('consultor','sdr') no banco. O bypass que aparecia em 120 lugares não protegia
uma pessoa, o que confirma a decisão do SaaS por outro caminho.
Handoff + backlog
-----------------
`handoff-2026-08-18b` traz o placar G-01…G-10 com todos os itens REVERIFICADOS no
código vivo (não repassados da doc), o mapa dos 5 padrões de bypass, os quatro
defeitos achados no caminho e o que falta, em ordem.
`gaps-backlog.md`: G-05 fechado, G-08 na metade, ambos com a investigação que
mostrou que nenhum dos dois era o que o backlog dizia.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ssaram a mentir O handoff estava em formato de relatório de sessão. Reescrito para o que a próxima sessão precisa primeiro: E3 é onde retoma, o rito, a régua e as 9 etapas logo na abertura; o que a sessão fez virou contexto abaixo. E0 — o veredito da régua ficou falso ------------------------------------ Dizia "reprovado no item 1 e no 3", porque as perguntas 6 e 7 estavam trancadas atrás de `canOperateProject`. O G-09 foi executado: os itens 1 e 3 passam NO CÓDIGO (falta o check ao vivo). O que segue reprovado é o item 4 — e agora se sabe onde (abaixo). E1 — aquele 🟡 nunca existiu ---------------------------- "Distribuição da conta nova — exige consultor" saiu de uma leitura incompleta da RLS: olhou `pending_ofx_update`/`_delete` (staff-only) e não viu as irmãs `pending_ofx_cliente_*`, que já estavam na baseline. Policies permissivas se somam por OR — basta uma dar caminho. E a UI expõe ao cliente: CasaDoGrupoShell → IngestaoCasaTab:139 → GroupIngestionTab, que renderiza o DistribuirContaPendenteModal (:292) com o botão "Distribuir" (:376). O diretório `forense/` engana — é pasta de componentes, não existe rota forense. Selo corrigido para ✅, e os ~10 min saem do consultor e entram no tempo dela. O achado que a E4–E6 vai encontrar em cada tela ----------------------------------------------- A pergunta nova do pente fino é "o cliente sozinho consegue interpretar o que vê?". Há resposta parcial, e é NÃO: 9 textos de tela mandam o cliente falar com um consultor que o modelo removeu. Sete em caminho vivo — a tela do Plano de Voo (AtoVCaminho.tsx:121,167), a narrativa de pacing do Cockpit (pacing/pacing-core.ts:513), a ingestão (ofx-scan-service.ts:460), o acesso (actions/conta/membership.ts:67) e o e-mail ao cliente (email-service.ts:268). As outras 2 estão num serviço sem callers. O sistema deixou o dono fazer tudo; o texto ainda aponta para alguém que não existe. Entra no backlog ANTES da E6 — senão a E6 sela 🔴 em tela que só precisa de copy nova. (Não confundir com "Consultor IA", o chat: é nome de feature.) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…removeu
O G-09 tirou o consultor do modelo (a autoridade passou a vir do vinculo), mas
a copy continuou apontando pra alguem que nao existe mais. Sob SaaS, tela que
manda "falar com o consultor" e trabalho sem dono — o 21 lugares varridos aqui.
O que mudou, por classe:
- Cockpit (pacing-core): o veredito de risco mandava "sentar com o consultor
para recalibrar". Agora termina em acao-raiz de verdade (R4): alavanca nova,
e o caminho e Iniciativas.
- Plano de Voo (relatorio, ato V, PDF): a legenda de "atraso critico" repetia o
mesmo; a meta dizia-se "calibrada pelo consultor" quando quem calibra e o
motor com a historia da propria empresa; e o dia a dia era "conduzido junto ao
seu consultor" quando na verdade acontece no Cockpit e nas Iniciativas.
- Capa e fecho do documento: o bloco rotulado "Consultor responsavel" mostra, no
codigo, quem GEROU o documento (fetchConsultor(userId)) — que sob SaaS e o
proprio dono. Trocar por "Suporte ATR" mentiria igual; o rotulo honesto nos
dois mundos e "Gerado por". Fallbacks de nome "Consultor ATR" -> "ATR OS".
- Ingestao, acesso e e-mail: o erro de distribuicao de OFX mandava "avise seu
consultor"; o de acesso ao grupo, "fale com o consultor" — quando hoje o dono
convida em Minha Conta > Empresa > Pessoas (inviteToGroupAction). O rodape do
e-mail idem.
- Proximos passos do relatorio: "recalibragem ... em nova rodada de consultoria".
Deixado de proposito, porque nao e copy:
- "Parecer do consultor" — campo humano real, escrito no WorkflowControls e
escondido do dono por padrao (AnalysisPageShell:59). Decisao de produto.
- email-service.ts:216 ("seu consultor responsavel e X") — X vem de
project.created_by, que num signup self-service e o proprio cliente. O defeito
ali e a FONTE da identidade, nao a frase; remendar a copy esconderia o bug.
- ofx-import-service.ts:20 — servico sem nenhum caller (codigo morto).
- COMPROMISSO_ATR — promessa comercial de acompanhamento humano. Nao e minha
decisao mudar o que a ATR promete.
Prova: eslint com 0 erros novos (os 3 hits nas linhas tocadas sao
text-[var(--...)] que ja existiam no HEAD); tsc --noEmit EXIT=0; suite 181
arquivos / 1.885 testes verde. Build nao rodado de proposito: dev server no ar
em :3000, e next build derruba as rotas dele.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Eram 21 lugares, nao 9 — a contagem anterior grepou frases prontas e nao pegou a familia de ROTULOS, onde estava o pior caso: a capa do Plano de Voo dizia "Consultor responsavel" sobre o nome de quem GEROU o documento, que sob SaaS e o proprio dono. Vira "Gerado por". Registra tambem a decisao do Lucas de manter o COMPROMISSO_ATR (e oferta, nao defeito) pra E6 nao re-levantar, e o motivo de 3 outros itens NAO terem sido tocados. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…quem veio busca-lo O motor de fechamento e solido: amortizacao SAC/Price, match de parcela com tolerancia, snapshot imutavel versionado, stale-by-event. O caminho do cliente nao e. O achado central: pra separar receita de custo do dinheiro, o gate pede o VALOR DE FACE da antecipacao. O OFX credita o liquido; a face mora no borderô do banco. Sem ela o mes nao fecha. E a E0 diz, textualmente, que ninguem na Casa Pilar sabe quanto o desconto de duplicatas custa — o sistema pergunta a cliente exatamente o que ela veio perguntar ao sistema. Sozinha, ela trava ali. Medido em producao (scripts/diag-fechamento-e3.ts, somente leitura): - 91% dos meses fechados tinham pendencia que BLOQUEIA o fechamento; na Vertimetal, 31 de 31. Na Di Forni, 0 de 3 — o gate e funcao do PERFIL do cliente, nao do sistema, mesmo padrao que a E2 achou na cauda. - 97% dos meses foram fechados mais de uma vez. Mas a distribuicao desmente a leitura obvia: 27 meses em v5, com ~30 fechamentos no MESMO DIA, quatro vezes. Nao e o cliente reapurando — e o historico inteiro sendo refechado em massa por drift de catalogo/motor, via script com service key. Sob SaaS nao existe quem rode esse script. - 0 projetos passaram de 'rascunho' na escada de publicacao — e o motivo esta no codigo: ResultsTab declara o prop onPublishDRE e nunca o usa; PublishDREModal nao tem ponto de montagem. A cascata que auto-conclui as analises #2/#5/#8/#10 nunca dispara, e a ferramenta que da contexto a IA le justamente essas. Custo: ~5h para a Casa Pilar, ~40% delas fora do sistema (cacando o valor de face no banco). Acumulado E1+E2+E3 = ~11h30, e ela ainda nao viu uma resposta. 7 achados (E3-A..E3-G). A maior alavanca e barata: herdar prazo e tipo da antecipacao do ultimo mes declarado, no mesmo padrao sugerir+confirmar que a auto-linkagem de parcelas ja usa. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…de começar
Fecha a varredura da jornada do cliente (E0-E8), iniciada em 17/ago. Nenhuma
linha de src/ foi tocada: foi auditoria, não conserto, por decisão do Lucas.
O VEREDITO: o produto não está imaturo — está desconectado.
A cadeia das 7 perguntas quebra em quatro dos sete elos. Mas dos 24 achados
críticos, 10 são fiação: a peça existe, está correta, e lê a fonte errada — ou
não está ligada em nada. Três consertos já estão escritos no repositório e nunca
foram repontados (snapshotAprovadoVigente, consultorPronto, o padrão .range()).
Os achados que sustentam isso:
- E6-A: a dona gera o Plano de Voo e não consegue travar a meta nem abrir o
documento. documento/page.tsx é o único mount de WorkflowControls, único
caller de approvePlanoVooV2Action, atrás de um redirect por PRIVILEGED_ROLES.
Isso derruba o critério 3 do E0 ("nenhum elo exige alguém da ATR"), que o
handoff de 18/ago dava como aprovado.
- E6-C/E6-D: o Consultor IA nunca terá ferramentas — teto estrutural de 10
análises concluídas contra um limiar de 30. A régua substituta (consultorPronto)
existe, a flag está ON global desde maio, o dossiê é carimbado, e as duas rotas
de chat não a leem.
- E4-A/E4-C: a Curva ABC soma débito cru de 32 meses sem as colunas da DRE; o
Ponto de Equilíbrio calcula sobre o mês corrente parcial. Ambos saem, e saem
errados.
- E5-A/E4-J: a concentração de clientes é calculada sobre 1.000 linhas, sem
order — em duas telas. O teto do PostgREST está documentado no próprio repo e
contornado em 11 outros leitores.
- E7-A/E7-B: o sistema nunca chama a cliente de volta. O lembrete mensal foi
construído e está parado por quatro bloqueios empilhados, incluindo gravar numa
tabela sem nenhum leitor.
Entregue:
- RELATORIO-TECNICO.md — o compilado autocontido: método, custos medidos, a
tabela mestra dos 52 achados, o backlog em 6 blocos, decisões travadas.
- README.md — porta de entrada da pasta.
- 04 a 08 — as etapas novas (diagnóstico, simulador, plano/cockpit/IA, cadência,
veredito).
- Anexos de evidência (arquivo:linha) em E1-E7, para reauditar sem refazer.
- E3-B registrado como decisão travada: o switch face x taxa no gate, com a
fórmula e a armadilha do religamento do Nível 1 (que erra em silêncio, para
menos).
Correções aplicadas na conferência final — um checador de caminhos sobre as 89
referências citadas pegou três erros, dois herdados dos docs originais:
GiroView.tsx:281-286 -> :265-268; lib/partes-relacionadas/receita-ficha.ts não
existe (é lib/receita-ficha.ts); e E2-A já tinha sido executado em 66771e8.
Handoff canônico novo (handoff-2026-08-20) com a recomendação de sequência:
começar pela Fatia A (E6-D, E6-A, E6-B) porque a Vertímetal já tem 31 meses
fechados e permite o check ao vivo que a trilha inteira ficou devendo — e não
pelo achado mais grave (E3-B), que só se prova num cliente em onboarding.
Fora do commit por decisão: docs/business/*.md (proposta comercial).
Dívida declarada: E5b (Caixa & Projeção) não foi auditada — em redesenho.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Executa o item 1, a cobrança dos 12 meses e o E6-A ampliado do plano de correção do pente fino (docs/valor/pente-fino/PLANO-DE-CORRECAO.md). O QUE ESTAVA QUEBRADO, na ordem em que a dona encontrava: 1. Ela fechava meses e o sistema NUNCA dizia quantos faltavam nem quais. `consultorPronto` recebia a contagem e a lista era descartada na chamada — a tela era estruturalmente incapaz de nomear os meses. 2. Ao chegar em 12, nada avisava que o Plano tinha destravado. 3. Se achasse o Plano sozinha, gerava a meta e NÃO conseguia travá-la: o único caller de `approvePlanoVooV2Action` vivia numa página que expulsa quem não é PRIVILEGED_ROLES — embora a action já fosse client-first. 4. Se perguntasse ao chat sobre o próprio caixa, com 12 meses fechados, a IA era instruída a "NÃO interpretar dados financeiros". O (4) tinha três camadas, uma dentro da outra. O contador `analyses_completed` é ZERO em todo projeto real — os únicos escritores (`/financeiro/concluir`, `/financeiro/publicar`) não têm caller no front. Com zero, o primeiro `if` da máquina de fases vencia sempre e a fase ficava presa em `onboarding`, cujo guardrail proíbe leitura financeira. O gate de tools (`>= 30`) era só o sintoma visível. D10 — o modelo de 30 análises sai do sistema: - a FASE passa a vir da cobertura da janela de 12 meses, não da contagem - os 6 gates inline viram `isModoConsultor()`, que já existia e já estava certo - some o "X/30 análises" que chegava na cara da cliente, e o guardrail deixa de proibir falar do número: o limite certo é não PROJETAR sobre série curta - `analyses_completed` e `module_progress` saem do dossiê — eram escritos e nunca lidos, e custavam uma ida ao banco por compile D3 — a escada de publicação é aposentada (8 caminhos): o mês fecha por `apurar -> gate -> preview -> concluir`, e quem grava o snapshot é o POST /dre/fechar-mes. A escada era caminho paralelo e morto. - `get_dre_readiness` parava em `module_analyses.publish_status`, sempre 'rascunho' — a tool de IA dizia "sistema bloqueado" para quem tem 32 meses - `vw_company_context` carregava `30 AS analyses_total` literal em SQL - a tela da DRE disparava um RPC por load para alimentar prop nunca renderizado A cobrança (passos 5 e 9 da jornada): `Readiness` carrega `mesesFaltantes`, e a Apuração ganha a faixa que nomeia os meses e leva até cada um. Ao fechar o 12º, a mesma faixa vira o sinal de que o Plano destravou. Trocar a assinatura em vez de somar campo opcional foi decisão: opcional apagaria a cobrança em silêncio. E6-A + D11 (passos 10 e 11): `TravarMetaCard` no overview, sem gate de papel — `travarMetaAction` checa vínculo e qualidade no caminho de ESCRITA. Ajustar a receita cria VERSÃO NOVA, para o que o motor propôs continuar registrado ao lado do que ela escolheu. `ajustarReceitaDaMeta` é pura e roda igual no client (preview) e no server (gravação). Correção à D11: só o RESULTADO segue a receita, e só na fase `aproximacao`. Margem e endividamento são metas de NÍVEL por lei do modelo-meta-pacing §4 — a tela diz o que não se move em vez de fingir. Guarda nova: teste de paridade registro × manifesto de tools. Deletar uma tool sem tirar o anúncio do prompt faz a IA chamar ferramenta inexistente em runtime, no meio da conversa da cliente — foi o que quase aconteceu aqui. Duas migrations aplicadas no remoto e conferidas no banco vivo (a view voltou com 17 colunas). SNAPSHOT.md marcado como OBSOLETO: o dump é anterior a elas. Build limpo · 1906 testes verdes · zero lint novo. Falta o check ao vivo — toda a prova aqui é estática. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ei do backlog O relatório do pente fino respondeu "o que está quebrado". Este doc responde "em que ordem consertar", e a ordem mudou por causa de duas decisões do Lucas. D1 — autonomia total desde o dia 1: "tudo o que o sistema faz deve ser feito 100% pelo cliente; ter ou não consultor não diferencia. Se ele não quiser fazer, contrata a gente — mas se quiser seguir sozinho, o sistema funciona." Isso INVERTE o §9 do relatório, que pôs "baratear a entrada" em P4. Sob autonomia total a cliente faz ingestão, categorização e apuração na PRIMEIRA sessão: se fechar 32 meses são 32 wizards, ela desiste antes de ver o primeiro número. Consertar a Curva ABC de uma DRE que ela nunca vai gerar não a segura. Três achados sobem de P4 para P2 — e o pior deles é o E3-D: refechar histórico exige service key, e sob D1 não existe quem rode. A jornada canônica (§0) são 14 passos, do OFX ao chat. Ela é a lei: o que não a serve, sai. O E7-D (cadência trimestral) saiu por isso — deixou de ser decisão pendente. Dois achados NOVOS, fora dos 52, encontrados ao conferir a jornada no código: - o sistema TRANCA os 12 meses mas não os COBRA: a lista de meses faltantes era descartada na chamada de `consultorPronto` - a meta NÃO é editável: as 7 actions do Plano de Voo não movem o número. A E6 parou em "ela não abre a porta" e nunca testou o que teria depois dela E o que já estava certo e eu ia mexer sem precisar: `janelaPorMesDeEntrada` é a conta exata do Lucas (entrada ago/2026 => jul/2026…ago/2025), a âncora na ENTRADA evita a janela deslizar e re-trancar o Plano, e o endividamento pelo gate já está ligado. Inclui o eixo B, que o relatório não viu: como a cliente COMPRA e PAGA. Não há dependência de pagamento, tabela de assinatura nem auto-cadastro — a oferta "Sistema" avulso da proposta hoje não tem máquina. §3.3 registra o que já foi executado (commit anterior) e o que espera check ao vivo. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…dilhas do caminho Handoff canônico da sessão que executou o Bloco 0 quase inteiro. Lidera com a retomada, como é o padrão da casa: **pega no E3-B**, que é o último item que ainda quebra a corrente — e o único que decide se o check ao vivo pode usar uma empresa real do ICP (quem desconta duplicata não fecha um mês hoje). §5 traz tudo que a implementação precisa sem reabrir o relatório: a conta (`face = líquido / (1 − taxa×prazo/30)`), os 3 invariantes de regressão, os arquivos a tocar, e a armadilha — o caminho "cliente informa a taxa" JÁ existe no motor e está morto; religá-lo como está erra em silêncio e PARA MENOS. §4 registra as 6 armadilhas que valem mais que os consertos, todas encontradas nesta sessão: - a suíte passou 1887 testes com erro de sintaxe (nenhum teste importava os 2 arquivos; quem pegou foi o tsc) - `.next/dev/types/` NÃO se regenera no build — o build lê e falha citando rota deletada; `rm -rf .next` depois de deletar rota - campo obrigatório (não opcional) fez o compilador achar 5 construtores de `Readiness` que o grep não achou - classe Tailwind inexistente passa no lint (`text-alert-red` não existe) - o hook de pre-commit leva ~3 min; dê 10 ao commit §7 deixa o estado do banco explícito: as 2 migrations estão aplicadas e conferidas no banco vivo (a view voltou com 17 colunas), mas `db/snapshot/` está 🔴 OBSOLETO e o `ESTRUTURA.md` NÃO foi regerado de propósito — ele é dump × código, e regerar sobre dump velho descreveria a view antiga. CLAUDE.md passa a apontar o plano de correção como a lei do trabalho, com o aviso de que a ORDEM do relatório do pente fino foi substituída pela D1. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…s novo `lerMeta` ordenava por `version desc` sem filtro de status. Como `saveRevisedVersionAction` grava a edicao do plano como `status='revisado'` com `version = max+1`, a primeira edicao feita DEPOIS de a dona travar a meta roubava a referencia — e nada na tela dizia que o numero havia mudado de dono. Quatro consumidores liam por ali: Cockpit, Capital de Giro, Simulador e o motor de Iniciativas. Todos herdam o conserto sem mudanca propria. Pior que errar: quando o vigente e um documento v2, o parse falha e a meta some — mesmo sintoma de "nao ha plano aprovado", indistinguivel na tela. O predicado de "vigente" virou `queryPlanoVigente`, num lugar so. Escrever a query duas vezes foi como o filtro de status se perdeu na primeira; agora quem precisar de outra coluna passa por la em vez de remontar a query. Os testes travam o FILTRO, nao o resultado — um fake que devolvesse so a linha certa passaria com o bug de volta. Provado por mutacao: repondo `version desc`, o teste falha. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
O extrato credita o LIQUIDO; a face esta no bordero, que a maior parte do ICP
nao tem em maos na hora de fechar. Ate aqui um campo de formulario trancava a
apuracao — e com ela as 7 perguntas do produto — para todo cliente que desconta
duplicata. Era o `antValido` do gate exigindo a face.
A face deixa de ser obrigatoria e vira um switch DO MES: "tenho o bordero"
(face por operacao) x "sei a taxa que pago" (o sistema deriva a face do
liquido). Pede % AO MES, como o banco cota; o prazo faz a conversao.
t_periodo = taxa_a.m. x prazo_dias / 30
face = liquido / (1 - t_periodo)
100k a 2% a.m. por 45 dias -> face 103.092,78, desagio 3.092,78, ~27,6% a.a.
A ARMADILHA, e por que ela ficou impossivel em vez de documentada:
O caminho "cliente informa a taxa" ja existia (Nivel 1, `nivelGeral`) e estava
morto. Religa-lo como estava erra em silencio e PARA MENOS: sem face,
`valorBrutoDe` cai no `valor_bruto_real`, que e o liquido do extrato, e o
forward faz `desagio = liquido x taxa` — base errada, liquido resolvido que nao
bate com o extrato. A taxa incide sobre a FACE, dai a divisao por (1 - t).
Por isso `resolverAntecipacaoPorTaxaDeclarada` e funcao IRMA, nao um modo da
antiga: o caminho da taxa nunca chama `valorBrutoDe`. Reintroduzir o bug exige
reescrever a funcao, nao esquecer um `if`. Provado por mutacao: repondo o
forward, dois testes caem.
Os invariantes travados em teste:
1. o liquido nunca e recalculado — e o credito do extrato, ao centavo;
2. cada linha deriva a propria face pelo proprio credito (por isso o toggle
agregado x detalhado sai da tela no modo taxa — nao muda um centavo);
3. tudo sai com `fonte: "estimada_taxa"`, e a tela e obrigada a rotular;
4. face - desagio = liquido ao centavo — o efeito na DRE e exatamente o
dinheiro que entrou na conta. E o que torna uma face ESTIMADA segura de
publicar em regime de caixa.
O arredondamento fecha pelo desagio, nao pela face, para que a identidade valha.
Taxa/prazo impossiveis (t >= 1) nao estimam nada: bloqueiam o gate, em vez de
gravar um numero que ninguem consegue auditar depois.
Rastreado ate o snapshot fechado antes de confiar: a RPC
`calculate_monthly_dre_v3` le `resultado->>'total_desagio'`/`'total_bruto'`, o
`dre-canonico` le `det.ant.resultado` e o impeditivo do gate testa
`resultado IS NOT NULL` — todos agnosticos ao modo. Nada recalcula a partir de
`dados`, que era onde o desagio poderia sumir calado.
Migration 20260820030000 (aplicada e conferida no banco vivo): o CHECK de
`dre_detalhamento.modo` ganha `'por_taxa'`. E modo proprio de proposito — quem
ler 'agregado' depois tem o direito de assumir que a face veio do dono.
Falta o check ao vivo: a tela nao foi vista rodando.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Updates to Preview Branch (feat/partes-relacionadas-e-regra-token) ↗︎
Tasks are run on every commit but only new migration files are pushed.
View logs for this Workflow Run ↗︎. |
O gate `gerar-estrutura.ts --check` falhava na CI. Provado por worktree que a defasagem NAO veio dos commits do E3-B/E5-B: em `2849b23` — ultimo commit da sessao da A1, antes deles — o gate ja falhava. A A1 deletou 8 caminhos de codigo (escada de publicacao, tools de IA) sem regerar o mapa, e ninguem viu porque esta branch ainda nao tinha PR: a CI nunca rodou nela. O diff e so contagem de usos, e conta a historia das delecoes: `module_analyses` 30->19, `get_dre_readiness` 3->1, `project_modules` 22->19. `plano_voo_snapshots` sobe porque o predicado de "vigente" virou funcao compartilhada (E5-B). A ressalva da sessao passada — "nao regerar, o dump esta velho" — era razoavel mas nao se confirmou: nada derivado do dump mudou (113 tabelas, 13 views, 73 funcoes, identicos). O arquivo ja descrevia o dump de 18/ago e continua descrevendo; regerar so atualizou o que vem do CODIGO. As partes derivadas do dump seguem velhas ate o re-dump — inclusive `vw_company_context`, que no banco vivo ja perdeu as 2 colunas do placar. Segue aberto (pre-existente, nao desta leva): 4 `.from()` para tabela inexistente — budget_items, budgets, pulse_checks, system_notifications. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
21 commits acumulados nesta branch. O eixo é a jornada canônica do cliente
(
docs/valor/pente-fino/PLANO-DE-CORRECAO.md§0): tudo aqui serve a corrente quevai do extrato até a meta travada.
O que fecha nesta leva
E3-B — o switch da antecipação. O extrato credita o líquido; a face está no
borderô, que a maior parte do ICP não tem em mãos. Um campo de formulário
trancava a apuração inteira para todo cliente que desconta duplicata. A face
deixa de ser obrigatória: quem sabe a taxa declara % ao mês + prazo, e o sistema
deriva a face do líquido (
face = líquido / (1 − taxa × prazo/30)).A armadilha está tratada estruturalmente: o caminho da taxa é função irmã do
motor multinível e nunca chama
valorBrutoDe— onde o líquido do extrato viravaface e o deságio saía errado, em silêncio e para menos. Provado por mutação.
E5-B — a meta do pacing vem do plano vigente.
lerMetaordenava porversion descsem filtro de status; a primeira edição do plano feita depoisde a dona travar a meta roubava a referência de 4 telas (Cockpit, Capital de
Giro, Simulador, motor de Iniciativas), sem nada dizer.
A1 (já na branch) — o modelo morto de 30 análises fora do sistema, a escada
de publicação aposentada, a cobrança dos 12 meses pelo nome, e a dona travando a
própria meta.
Segurança (já na branch) — 31 policies que liberavam por estar logado.
Banco
20260820030000amplia o CHECK dedre_detalhamento.modocom'por_taxa'.Já aplicada no remoto e conferida no banco vivo (prova não-destrutiva com
controle registrada no
SNAPSHOT.md). As de 20/ago também já estão aplicadas.db/snapshot/segue 🔴 obsoleto (dump de 18/ago) — pede re-dump com Docker,e o
db/ESTRUTURA.mdsó deve ser regerado depois dele.Prova
tsczero erros · 1922 testes verdes · build limpo · zero erros de eslintnovos nos arquivos tocados.
O que NÃO está provado
O check ao vivo. Nada aqui foi visto rodando — e o
metodo.mddiz que o gateé o check ao vivo. O roteiro está no handoff: subir OFX → categorizar → ver a
faixa cobrar os meses pelo nome → fechar um mês com antecipação pelo modo taxa
→ travar a meta mexendo no número → o Cockpit popular → perguntar ao chat.
Duas armadilhas do roteiro: o dossiê tem TTL de 24h (feche um mês antes de
perguntar ao chat), e o visual do switch da antecipação ainda não teve um par de
olhos humanos.
🤖 Generated with Claude Code