Análise Sênior · Módulo Agenda Estado pós-bateria de testes C1–C13 · 2026-05-20 · Sistema AgênciaPSI

Files
142
Arquivos no escopo agenda
LOC
15.6k
Linhas em hotspots-chave
Bugs/dia
14
Corrigidos em 20/05
Commits/dia
15
Working tree clean

0Sumário Executivo

O módulo de agenda do AgênciaPSI atravessou uma rodada estrutural de validação via 13 cenários do documento vivo src/docs/agenda-compromisso-financeiro-cenarios.html. A bateria expôs 14 bugs reais em apenas um dia — todos corrigidos — e revelou um padrão recorrente: regressões silenciosas em fluxos paralelos, particularmente em interações com billing_contracts e financial_records.

A engenharia do módulo é funcionalmente robusta — os fluxos críticos (status change, pacote saldo, pacote upfront, multa, antecipação, edit imutável) operam corretamente após os fixes. Mas a base de código carrega sintomas que devem ser endereçados antes da replicação para Rail e Clínica, sob risco de duplicação de dívida.

Verdict resumido: arquitetura sólida em conceito, dívida técnica acumulada em execução. Refatoração de 3 hotspots e adoção de tipagem forte resolveriam ≥60% dos bugs futuros antes de virarem produção. A replicação Rail/Clínica é o ponto natural de inflexão para consolidar.

Top 5 achados

  1. 3 hotspots ultrapassam 2,8k LOC cadaAgendaEventDialog.vue (6.070), MelissaLayout.vue (4.331), AgendaTerapeutaPage.vue (3.567). Refator sustentado é inviável neste estado. P0
  2. Lógica de status change triplicada entre Melissa, Rail e Clínica. Bugs corrigidos hoje em Melissa ainda persistem nas outras duas implementações. P0
  3. Gotcha billing_contracts.updated_at — coluna inexistente. UPDATEs falhavam silenciosamente em Promise.allSettled. Patch tipo "trigger SQL" eliminaria a categoria inteira. P1
  4. Snapshot stale em popovereventoSelecionado.value é cópia, não referência reativa. Padrão repetido em outros componentes do Melissa. Ergonomia ruim para mutações otimistas. P1
  5. Audit trail acumulando ruído — ciclos antecipar/revogar/realizar geram records cancelled que poluem a view /financeiro sem filtro. Falta UI dedicada de auditoria. P2

Índice

  1. Estado atual — métricas e estrutura
  2. Pontos fortes
  3. Dívidas técnicas / code smells
  4. Issues de UX
  5. Riscos arquiteturais
  6. Recomendações priorizadas (P0–P3)
  7. Roadmap proposto
  8. Apêndices — bugs do dia, pendências, commits

1Estado atual

1.1 Distribuição de complexidade (hotspots)

Arquivo LOC Tipo Observação
AgendaEventDialog.vue 6.070 Componente Vue monolítico ≥7 responsabilidades distintas: cadastro, recorrência, billing, multa, pacote, lock, preview
MelissaLayout.vue 4.331 Layout container Container + ~30 handlers + 8 dialogs montados; deveria ser shell
AgendaTerapeutaPage.vue 3.567 Página Rail (legacy) Implementação paralela com lógica duplicada
useMelissaAgenda.js 2.863 Composable monolítico Bulk-load, normalize, handlers, status change, decisions, applies — tudo aqui
AgendaClinicaPage.vue 2.811 Página Clínica (legacy) 3ª implementação paralela; receberá os mesmos bugs
MelissaEventoPanel.vue 1.010 Popover Aceitável, mas concentra lógica de derivação (paymentLabel, contractInfo, ações)
useAgendaEventLifecycle.js 685 Composable de lifecycle Carregamento, edit, delete; saudável em tamanho
AgendaStatusChangeConfirmDialog.vue 671 Dialog dedicado Recém-ampliado com bloco reverse (Fase 5); ainda dentro do aceitável

Total nos hotspots acima: ~22k LOC. Em escala de manutenção, qualquer arquivo >1.000 LOC é candidato a refator; >2.500 LOC é débito crítico — toda navegação demanda Ctrl+F.

1.2 Estrutura de pastas (recap)

src/
├── features/agenda/
│   ├── components/        (15 .vue — DialogV2, Toolbar, Calendar, etc)
│   ├── composables/       (20 .js — lifecycle, events, services, etc)
│   └── pages/             (5 .vue — Terapeuta, Clínica, Recorrencias, etc)
├── layout/melissa/
│   ├── composables/       (useMelissaAgenda 2.863 LOC)
│   ├── MelissaLayout.vue  (shell + handlers)
│   ├── MelissaAgenda.vue  (FullCalendar wrapper)
│   ├── MelissaEventoPanel (popover)
│   └── ...
└── components/agenda/     (AgendaEventoFinanceiroPanel, etc)

1.3 Cobertura de testes

src/features/agenda/composables/__tests__/ tem 7 specs Vitest cobrindo composables principais (events, lifecycle, composer, picker, recurrence). Não há testes E2E. Toda validação de fluxo financeiro (status change, pacote, antecipar) depende de bateria manual contra o documento vivo HTML.

Métrica de risco: 14 bugs encontrados num único dia de teste manual num único persona (Melissa). Extrapolando para Rail/Clínica sem refator antes, esperar 25–35 bugs equivalentes na replicação.

2Pontos fortes

Análise reconhece méritos antes de criticar. O que está bem feito:

2.1 Cobertura de cenários documentada

O arquivo src/docs/agenda-compromisso-financeiro-cenarios.html é uma boa prática rara: doc vivo que descreve cada cenário com mockup interativo + critério de teste. Funciona como spec executável informal. O addendum de C10 que adicionamos hoje preservou o histórico de divergências. Manter

2.2 Audit trail em financial_records.notes

Todas as transições de cancelamento, reversão e revogação registram entrada cronológica em notes com formato [YYYY-MM-DD] motivo. Permite reconstruir o histórico financeiro de qualquer sessão. Estrutura simples mas efetiva — não criou tabela de auditoria paralela. Manter

2.3 Reverse transition trava (recém-implementada)

O dialog AgendaStatusChangeConfirmDialog agora cobre 4 contextos distintos: realizada (avulsa/pacote), faltou/cancelado (com multa+saldo), realizada com paid pré-existente (antecipação), e reversão para agendado (com cancelar records + devolver saldo). É o ponto único de decisão para mudanças com impacto financeiro. Manter

2.4 Bubble @cobranca-atualizada

Sub-componentes (panel financeiro, dialog) emitem evento que sobe até MelissaLayout e dispara M.refetch(). Padrão limpo para propagar updates de pagamento sem acoplar pais e filhos via store global. Manter — replicar em Rail/Clínica

2.5 Lock em sessão encerrada

Sessões em cancelado/faltou agora bloqueiam "Editar sessão" + transições de status (exceto "Agendada" como caminho explícito de recuperação) + label e badge cientes do estado. Evita operações financeiras inadvertidas em sessões que não aconteceram. Manter

2.6 Schema com constraints adequadas

financial_exceptions_charge_chk restringe valores possíveis de charge_mode. financial_records.status_check enumera estados válidos. Constraints de check ao invés de validação apenas em código — defesa em profundidade. Manter

2.7 Quick-create inline

Em vez de navegar para outro form quando falta uma dep (serviço, convênio, paciente), abre quick-create por cima. Preserva contexto do usuário. Padrão consistente. Manter — padrão de design

2.8 Convenção de variantes visuais

Cores semânticas consistentes — --ok (verde realizada), --warn (amarelo falta), --danger (vermelho cancelar), --info (azul agendada recém-adicionada). Padrão se mantém entre popover, dialog e calendário. Manter

3Dívidas técnicas / code smells

3.1 Monólitos Vue (≥2.500 LOC)

AgendaEventDialog.vue com 6k LOC concentra: cadastro de evento, recorrência, billing config, multas, pacote saldo/upfront, lock de cobrança emitida, preview da série, edição de ocorrência única vs todos. Sete responsabilidades distintas em um único componente — viola SRP.

Sintomas operacionais já observados: edição perigosa (qualquer alteração precisa varrer todo o arquivo), regressões frequentes em flows não-relacionados, teste unitário não consegue isolar um caso sem mockar 80% do contexto.

Quebra natural:

3.2 Triplicação de lógica (Melissa / Rail / Clínica)

Maior risco arquitetural identificado. Os bugs corrigidos hoje em useMelissaAgenda._applyStatusDecisions (cobrança dupla, updated_at gotcha, link universal) não foram propagados para AgendaTerapeutaPage nem AgendaClinicaPage.

O caminho que vai dar errado: replicar manualmente os fixes para cada um dos 3 contextos. Multiplica esforço por 3 e introduz drift.

Caminho correto: extrair em useAgendaStatusChangeOrchestrator.js consumido pelos três (Melissa via composable, Rail/Clínica via importação direta). Tornar _applyStatusDecisions, _loadStatusChangeContext, _needsConfirmDialog e _applyStatusUpdateOnly em funções puras com deps por injeção.

3.3 Promise.allSettled escondendo falhas

Padrão recorrente: tasks.push(...); await Promise.allSettled(tasks). Quando uma das tasks falha, vira {status:'rejected'} e o toast warn genérico aparece — fácil de ignorar.

Caso real (corrigido hoje): UPDATE em billing_contracts com campo updated_at inexistente. Falha silenciosa por semanas. Foi descoberto manualmente quando o saldo não incrementava em teste E2E manual.

Política sugerida:

3.4 normalizeForMelissa whitelist silenciosa

A função normalizeForMelissa(r) retorna um objeto com campos explícitos. Campos no r original que não estão no return somem silenciosamente. Bug do dia: owner_id não estava no return → após o watch sync introduzido, virava null → INSERT em financial_records violava NOT NULL.

Memória existente (project_pickdbfields_whitelist) documenta bug análogo no pickDbFields. Padrão repetido.

Mitigação imediata: documentar e auditar manualmente todos os campos necessários. Mitigação estrutural: TypeScript ou JSDoc tipado no return — o linter sinalizaria campos faltantes antes do runtime.

3.5 Snapshot stale em refs reativas

eventoSelecionado.value = ev copia a referência. Quando o eventos computed recalcula com novo objeto, a ref guardada não acompanha. Padrão repetido em outros lugares do Melissa (já há memória documentando).

Mitigação aplicada hoje: watch em M.eventos com lookup por id + recurrence_id/date (cobre transição virtual→materializada).

Mitigação estrutural: trocar o pattern por const selectedId = ref(null) + const selectedEvent = computed(() => eventos.value.find(e => e.id === selectedId.value)). Reatividade nativa, zero watches, zero race conditions.

3 · Dívidas técnicas (continuação)

3.6 Race conditions em refetch()

_reloadRange dispara queries paralelas (eventos, virtuais, bloqueios, payment state, propagação cross-week). Operações UI sequenciais rápidas (antecipar→revogar→antecipar) podem ler ctx antes do refetch anterior propagar, levando a decrements/increments com base em valores stale.

Mitigação aplicada hoje no bloco reverseRestoreSaldo: refetch explícito do billing_contracts.sessions_used direto do DB imediatamente antes do UPDATE. Padrão "lê fresh, escreve consciente".

Mitigação estrutural: mover lógica de increment/decrement de saldo para RPC server-side com lock pessimista (SELECT ... FOR UPDATE). Elimina race condition no nível de banco.

3.7 RPCs sem idempotência forte

create_financial_record_for_session foi corrigido para ignorar cancelled em idempotência (commit c23d0a5, já documentado em memória). Mas o handler do antecipar fazia UPDATE manual em record cancelled após chamar a RPC, reativando-o como paid. Audit trail polluído.

Princípio: RPCs financeiras nunca devem reusar records cancelados. Toda operação que cria cobrança gera record novo. Cancellation é terminal.

3.8 Pattern updated_at inconsistente entre tabelas

Algumas tabelas têm trigger set_updated_at automático (ex: financial_exceptions), outras não (billing_contracts). Código cliente assume incorretamente que todas têm. Foi origem direta do bug do updated_at.

Tabela atual:

Tabelatem updated_at?tem trigger?
financial_recordspresume-se sim
financial_exceptionstrg_financial_exceptions_updated_at
agenda_eventospresume-se sim
recurrence_rulespresume-se sim
billing_contracts

Recomendação: adicionar updated_at + trigger em billing_contracts via migration. Tornar consistente em todas as tabelas de domínio operacional.

3.9 RLS pode mascarar erros

UPDATEs em RLS-protected tables retornam silenciosamente 0 rows quando a policy filtra. Sem RETURNING explícito o cliente não detecta. No fluxo de status change atual, vários UPDATEs assumem que rodaram.

Mitigação: adicionar .select() ou .select('id').single() em UPDATEs sensíveis; falhar explicitamente se 0 rows afetadas.

3.10 Estado distribuído sem fonte da verdade

Mesma informação (e.g. sessions_used) lida de múltiplas fontes: ctx.billingContract.sessions_used (snapshot do load), ev.contract.sessionsUsed (via ruleContractMap), DB fresh, cached em variáveis locais. Pontos de divergência são pontos de bug.

Princípio: single source of truth por operação. Antes de UPDATE crítico, fresh-fetch + uso somente da leitura recente. Em UIs reativas, derivar de um único store/computed.

4Issues de UX

4.1 Sobreposição semântica: Usar / Antecipar / Realizada

Em pacote saldo, três botões diferentes podem operar sobre a mesma sessão:

Cada um cobre um caso de uso ligeiramente diferente, mas o overlap confunde. Durante o teste do dia, usuário ficou perdido entre os três caminhos.

Proposta: unified action menu. Um único botão "Marcar sessão" abre menu contextual:

┌─ Marcar sessão como… ─────────────┐
│ ✓ Realizada                       │
│   ├─ Já recebi (PIX/dinheiro/...) │
│   └─ Cobrar depois (saldo/avulsa) │
│ ⚠ Faltou (+ multa/saldo)          │
│ ✕ Cancelar (+ regra)              │
├───────────────────────────────────┤
│ 💰 Antecipar pagamento (futura)   │
└───────────────────────────────────┘

4.2 Recovery único via "Agendada" — pouco descobrível

Sessão em cancelado tem 4 botões disabled (Realizada/Falta/ Reagendar/Cancelar) com tooltip "use Agendada para reativar". O aprendizado depende do hover no tooltip — primeiro encontro pode ser frustrante.

Proposta: badge inline ao lado dos botões disabled, ou banner amarelo no topo do popover: "Sessão encerrada. Clique Agendada para reabrir e permitir novas ações."

4.3 Múltiplos records cancelled poluindo audit

Ciclos antecipar/revogar/realizar geram records cancelled empilhados. Em /financeiro o filtro padrão .neq('status','cancelled') esconde do user normal, mas em queries de debug ou em telas administrativas a poluição aparece.

Propostas:

4.4 Dialog "Como cobrar?" / "Já recebi?" — refatorado, mas inspecionar mais flows

Hoje foi refatorado o bloco "Cobrança no pacote saldo" para ter sub-question explícita "A sessão já foi paga?". O mesmo padrão deve ser auditado em outros lugares onde aparece "método de pagamento" com opções mistas:

4.5 "A cobrar R$ X" enganoso para pacote saldo

Fix aplicado hoje: label muda para "Aguardando uso do pacote" (saldo) ou "Coberta pelo pacote (upfront)". Verificar consistência em:

4.6 Feedback de erro fraco em handlers async

Toasts genéricos "Falha ao processar mudança de status" não ajudam usuário. Quando RLS bloqueia ou constraint quebra, mensagem deveria ser específica:

4.7 Botão "Antecipar pagamento" → "Revogar pagamento" alternando

Padrão implementado hoje (alterna baseado em isAntecipacaoAtiva). Pode ser confuso para usuário que esquece do que clicou — botão "muda sozinho". Considerar:

4.8 Reverse dialog: "manter cobrança ativa" potencialmente perigoso

No dialog reverse, radio "Manter cobrança ativa" deixa user reativar sessão com record pending órfão. É uma escolha legítima mas raramente intencional. Considerar adicionar warning quando seleciona "manter".

5Riscos arquiteturais

5.1 Replicação Rail/Clínica sem refator = duplicação de dívida

Replicar os fixes do dia em AgendaTerapeutaPage e AgendaClinicaPage mantém as 3 implementações divergentes. Primeira sprint após replicação vai gastar tempo descobrindo "por que funciona em Melissa mas não em Clínica" (ou vice-versa).

Sequência recomendada antes da replicação:

  1. Extrair status change orchestrator para composable shared
  2. Migrar Melissa para usar o composable shared
  3. Testar (a bateria já existe — 13 cenários)
  4. Migrar Rail/Clínica para o composable shared (1 commit por persona)

5.2 Estado distribuído sem migration testada

Várias decisões de domínio são implícitas:

Não há documentação formal das invariantes do domínio. Consequência: cada bug exige reconstrução mental do que deveria ser válido.

Recomendação: documento de invariantes do domínio em Obsidian/Brain/wiki/agenda-invariantes.md + (futuramente) constraints SQL ou triggers checando os mais críticos no banco.

5.3 Multi-tenant: tenant_id manual em todo INSERT

Cada INSERT em financial_records, agenda_eventos, billing_contracts requer tenant_id explícito. Esquecer = constraint violation, ou pior, escrever no tenant errado.

Mitigação parcial: RLS bloqueia leitura cross-tenant. Mas writes ainda dependem do código cliente. Pattern de "service layer" com tenant injetado centralmente reduziria a área de risco.

5.4 Edge functions desacopladas da migration story

Edge functions (asaas-webhook, evolution-whatsapp, etc) operam direto no DB e podem deixar state inconsistente com o que o frontend esperar. Não foi escopo deste relatório, mas merece auditoria separada.

5.5 Ausência de feature flags

Cada fix do dia foi merged direto pra main e deploy implícito. Não há feature flag para experimentar "novo dialog reverse" em produção sem expor para todos. Em sistema com clientes pagantes, é fragil.

5.6 Backfills manuais via psql não rastreados

Durante o teste, vários UPDATE billing_contracts SET sessions_used=X foram aplicados manualmente para limpar estado. Em produção isso é impraticável e arriscado. Falta:

5.7 Indicador de saldo derivado vs persistido

billing_contracts.sessions_used é INTEIRO incrementado/ decrementado manualmente. Verdade "real" é o COUNT de records associados. Risco: drift entre os dois ao longo do tempo.

Alternativa: tornar sessions_used uma VIEW computed via COUNT(*) FROM financial_records WHERE billing_contract_id=X AND status IN ('paid','pending'). Performance pode requerer materialização ou índice; mas elimina classe inteira de bugs de sync.

6Recomendações priorizadas

Priorização: P0 = antes da próxima replicação (Rail/Clínica). P1 = sprint atual ou próximo. P2 = quando couber, valor compounding. P3 = ideal mas não bloqueante.

# Recomendação Prio Esforço Impacto
R1 Extrair status change orchestrator para composable shared useAgendaStatusChangeOrchestrator.js. Funções puras (loadContext, needsDialog, applyDecisions, applyStatusUpdate). Melissa migra primeiro, depois Rail/Clínica importam. P0 4–6h Alto · elimina trio
R2 Migration: adicionar updated_at + trigger em billing_contracts. Elimina o gotcha que custou horas hoje. Padroniza com outras tabelas. P0 30min Alto · elimina classe
R3 Auditar Promise.allSettled em fluxos financeiros. Trocar por awaits sequenciais com try/catch dedicado. Adicionar logger estruturado ([agenda/billing/saldo]). P0 2–3h Alto · visibilidade
R4 Documentar invariantes do domínio em Obsidian/Brain/wiki/agenda-invariantes.md. Estado válido de status × records × contract. Referência consultável. P0 1–2h Médio-alto · onboarding
R5 Refatorar AgendaEventDialog.vue em 5 sub-componentes (Shell, StepBasic, StepRecurrence, StepBilling, StepConfirm). Manter API atual; migration interna. P1 2–3 dias Alto · manutenção
R6 Trocar eventoSelecionado snapshot por selectedId + computed. Elimina snapshot stale. Replicar em outros refs do Melissa. P1 1–2h Médio · estabilidade
R7 Auditoria visual da sessão — drawer com timeline de records (pending/paid/cancelled), com cancelled colapsados por default. Reduz poluição em /financeiro. P1 1 dia Médio · UX
R8 RPCs server-side para increment/decrement de saldo com SELECT FOR UPDATE. Elimina race condition em fluxos rápidos. P1 3–4h Médio-alto · correctness
R9 Mensagens de erro específicas em handlers de status/billing. Catalogar erros típicos (RLS, constraint, state inválido). P1 2h Médio · UX
R10 TypeScript ou JSDoc tipado em normalizeForMelissa, pickDbFields e funções de transformação de dados. Lint flagga campos faltantes. P2 2–4h por área Alto longo prazo
R11 Testes E2E (Playwright) dos 13 cenários. Substitui bateria manual. CI roda em cada PR. P2 1 semana Alto · confiança
R12 Unified action menu "Marcar sessão" substituindo os 3 botões sobrepostos (Usar/Antecipar/Realizada). P2 1 dia Médio · clarity
R13 Feature flags via tenant_settings ou biblioteca específica. Permite rollout gradual de mudanças no dialog. P3 1 dia Baixo curto, alto longo
R14 sessions_used como VIEW computed em vez de coluna incrementada. Elimina drift de sincronia. Avaliar performance. P3 1–2 dias Alto correctness, médio risco
R15 Ferramenta de "data fix" versionada para correções administrativas em produção. Audit log obrigatório. P3 2–3 dias Alto operacional
Sequência sugerida: R2 (migration updated_at) → R1 (extrair orchestrator) → R4 (doc invariantes) → R3 (audit Promise.allSettled) → replicar Rail/Clínica. Tudo P0 entrega antes da próxima replicação reduz drasticamente o risco de regressão.

7Roadmap proposto

Sprint imediato (1–2 semanas) — Consolidação P0

  1. Dia 1 · R2 (migration updated_at + trigger billing_contracts) · 30 min
  2. Dia 1–2 · R3 (audit Promise.allSettled) · 2–3h
    • Grep Promise.allSettled em todo src/
    • Reescrever blocos financeiros para awaits sequenciais
    • Logger por domínio
  3. Dia 2–3 · R4 (doc invariantes) · 1–2h
  4. Dia 3–5 · R1 (extrair orchestrator) · 4–6h
  5. Dia 5–6 · Replicar fixes pra Rail (AgendaTerapeutaPage) via composable shared · 4–6h
  6. Dia 6–7 · Replicar fixes pra Clínica (AgendaClinicaPage) · 4–6h
  7. Dia 8 · Bateria de teste manual nos 3 personas · 1 dia

Sprint seguinte (2–3 semanas) — Refator P1

  1. R5 — Refator AgendaEventDialog em 5 sub-componentes (2–3 dias)
  2. R6 — Snapshot stale fix global (2h)
  3. R7 — Drawer de audit history (1 dia)
  4. R8 — RPCs increment/decrement com lock (3–4h)
  5. R9 — Mensagens de erro catalogadas (2h)
  6. Iteração de UX C12 (consolidar Usar/Antecipar/Realizada) · 1 dia

Próximo trimestre — Maturação P2

  1. R10 — JSDoc tipado em normalizers (incremental por arquivo)
  2. R11 — Testes E2E Playwright dos 13 cenários (1 semana)
  3. R12 — Unified action menu (refator UX)
  4. Auditoria de Edge Functions vs frontend (sprint dedicado)

Backlog longo prazo P3

Considerações finais

O módulo de agenda é o coração operacional do AgênciaPSI — é por onde o terapeuta vive o dia. Investimentos em estabilidade aqui têm retorno desproporcional: cada bug evitado é uma sessão real do paciente que não vira incidente.

A bateria de testes do dia provou que a metodologia funciona: 13 cenários documentados + bateria manual + iteração rápida descobriu mais bugs em 1 dia do que toda a auditoria anterior. Manter esse loop e automatizá-lo (R11) é o investimento de maior alavancagem.

O risco maior não é o que já encontramos — esses estão consertados. É o que ainda não foi exercitado em Rail e Clínica. A janela para consolidar antes de replicar é agora.

A boa notícia: a base é sólida. Os bugs encontrados foram de execução, não de design. As decisões arquiteturais maiores (SimplePractice-style invariantes, status change centralizado, audit trail em notes, separação avulsa/pacote) provaram-se corretas em uso real. O trabalho é polir, não reescrever.

Relatório gerado em 2026-05-20 · Análise pós-bateria C1–C13 · Sistema AgênciaPSI v5.0 ·
Baseado em: 15 commits do dia, 14 bugs corrigidos, 9 memórias de sessão, ~22k LOC inspecionadas nos hotspots.

8Apêndices

A · Bugs corrigidos em 2026-05-20

# Bug Severidade Commit
1 Cobrança dupla em multa: _applyStatusDecisions inseria multa mas deixava original pending Crítico d6423da
2 'fixed' vs 'fixed_fee' off-by-key em calcChargeAmount Médio (dormente) d6423da
3 Label "Como cobrar?" com options "Já recebi" misturadas — usuário marcou paid achando que era cobrar Alto UX 079509e
4 billing_contracts.updated_at inexistente causando UPDATE silently falhar em Promise.allSettled Crítico 16dfa02
5 Reverse transitions deixavam multa órfã (faltou→agendado) Alto 5684297
6 consumeSaldo não amarrava billing_contract_id ao evento Alto 3f3f2ac
7 Badge $ amber em sessão cancelada Médio 753182c
8 paymentLabel usava ev.price em vez de paymentAmount para pending Médio 753182c
9 "Gerar fatura" disponível em sessão encerrada Alto 753182c
10 _reloadRange não destruturado em _buildHandlers(deps) Médio 753182c
11 Faltou+multa-sem-consume não amarrava billing_contract_id Médio 5965b05
12 Re-antecipar reutilizava record cancelled (audit trail confuso) Alto b5e00a7
13 Popover snapshot stale após materialização virtual→real Alto b5e00a7 + f83315b
14 normalizeForMelissa não expunha owner_id → INSERT null violation Crítico 7d2a405

B · Pendências mapeadas em memória (pós-C13)

C · Commits do dia (20/05)

4da0bc2 HANDOFF + log: C12 deferred · testando C13
f83315b agenda: popover watch acompanha transicao virtual->materializada
7d2a405 agenda: normalizeForMelissa expoe owner_id/tenant_id/contract_id
b5e00a7 agenda: popover sincroniza com eventos + antecipar nao reusa cancelled
272c804 agenda: revogar antecipacao de pagamento
00c4168 agenda: C12 prep — detectar paid pre-existente em pacote saldo realizada
9ead3fd HANDOFF + log: C11 fechado · 4/4 sub-testes OK · proximo C12
5965b05 agenda: link universal pacote + refresh saldo no reverse
45984e8 agenda: label + badge cientes de pacote em sessoes state=none
3f3f2ac agenda: consumeSaldo agora amarra billing_contract_id no evento
5684297 agenda: reverse transition trava (Agendada apos artefatos)
16dfa02 agenda pacote saldo: fix root cause + sequential awaits
079509e agenda: dialog pacote saldo realizada — 2 sub-questions claras
7dc7dce wiki: log session C10 fechado completo
1e74a11 HANDOFF: C10 fechado · 5/5 sub-testes OK · proximo C11
753182c agenda: C10 pos-test fixes + lock sessao encerrada + addendum doc
3caf579 agenda popover: botao Agendada + fixes pos-C10/B
d6423da agenda: pre-C10 fix _applyStatusDecisions cancela pendingRecord

D · Status dos cenários documentados

#CenárioPersona testadaStatus
C1–C9Bloqueio, avulsas, recorrência, pacote, per_sessionMelissaOK (anteriormente)
C10Status change avulsa (5 sub-testes)MelissaOK
C11Status change pacote saldo (4 sub-testes)MelissaOK
C12Antecipar pagamentoMelissaDB OK · UX a iterar
C13Edit cobrada (imutabilidade)MelissaEm teste agora
Rail (AgendaTerapeutaPage)RailPendente — após refator
Clínica (AgendaClinicaPage)ClínicaPendente — após refator

E · Referências internas

Fim do relatório · 10 páginas · Geração local sem dependências externas · Para PDF, abrir no browser e Ctrl+P → Salvar como PDF.