Thanks to visit codestin.com
Credit goes to github.com

Skip to content

fix(inbox): a sugestão de resposta diz por que falhou, e a rejeitada sai da tela - #740

Open
paulolimajr77 wants to merge 1 commit into
melgarafael:mainfrom
paulolimajr77:fix/a-sugestao-diz-o-motivo-e-solta-a-tela
Open

fix(inbox): a sugestão de resposta diz por que falhou, e a rejeitada sai da tela#740
paulolimajr77 wants to merge 1 commit into
melgarafael:mainfrom
paulolimajr77:fix/a-sugestao-diz-o-motivo-e-solta-a-tela

Conversation

@paulolimajr77

Copy link
Copy Markdown
Contributor

Dois defeitos da tela de atendimento, medidos numa instalação real em 2026-09-12.

O que muda para quem atende

antes depois
Rejeitar uma sugestão não a tirava da tela — o texto ficava numa caixa desabilitada, sem botão de fechar A rejeitada solta o painel, que volta ao botão Sugerir resposta
Qualquer falha ao gerar virava a mesma frase: "Confira a publicação e a configuração do agente" A tela diz qual foi o motivo — e, quando não sabe, admite e registra

1. A sugestão rejeitada não saía da tela

ReplyReviewPanel pedia as cinco últimas sugestões da conversa e mostrava a
primeira sem olhar o estado dela:

order by created_at desc limit 5      ← app/api/v1/conversations/[id]/draft-reply/route.ts
const draft = query.data?.data.drafts[0];   ← ReplyReviewPanel.tsx

Rejeitar não fecha nada: a rejeitada continua sendo a mais recente. E não há
botão de fechar no componente — procurei, não existe.

O caso que trava de vez, e foi o que aconteceu: quem rejeita costuma pedir
outra em seguida. Se essa geração falha, nada substitui a rejeitada e a tela
fica presa naquele texto, indefinidamente.

Agora dismissed, stale e sent soltam o painel. failed não — a frase
dela é a única pista que sobra para quem não sabe por que a sugestão não veio.

Duas decisões que valem explicar:

  • Olha só a mais recente. A correção mais curta — procurar na lista a
    primeira que ainda sirva — ressuscitaria uma sugestão anterior logo depois de
    a atual ser rejeitada: um texto que o atendente acabou de recusar voltando
    sozinho para a tela. Há um caso cobrindo exatamente isso.
  • A confirmação da rejeição estava amarrada a draft existir. Sem ajustar
    junto, o conserto faria o aviso "o feedback será usado na próxima sugestão"
    sumir com a sugestão, e o clique em Rejeitar apenas esvaziaria a tela em
    silêncio.

2. O erro descartava a causa — e o identificador não levava a nada

A rota fazia } catch {sem nome. A causa morria ali, e três situações
sem nada em comum viravam a mesma frase, que manda conferir a publicação do
agente mesmo quando o problema é o provedor de IA fora do ar:

causa real o que era dito
reply_no_agent "Confira a publicação e a configuração do agente"
reply_context_unavailable idem
falha de IA, tempo esgotado, rede, SQL idem

E nada era registrado — nem logger, nem Sentry — enquanto a tela exibia o
requestId ao lado da mensagem, o que a faz parecer rastreável. Não era:
não havia nada gravado para procurar com aquele identificador. Um número que
promete e não entrega manda a pessoa procurar onde não há o que achar. Foi
assim que este defeito chegou até aqui: com o identificador em mãos e sem
caminho nenhum para a causa.

Agora motivoDaFalha nomeia as duas causas que generateReplyDraft lança de
propósito, o resto admite que é outra coisa, e a causa vai para logger.error
com organização, conversa e requestId.

O que eu medi e DESCARTEI

A primeira hipótese era que a falha vinha de enviar conteúdo vazio. Não se
sustenta
— os três caminhos já validavam, e está medido:

  • Composer.tsx:111 (if (!body || …) return) e :344 (botão desabilitado)
  • "Aprovar e enviar": disabled={… || !body.trim()}
  • "Sugerir resposta": não tem campo nenhum; o POST manda {}

Não falta validação. Falta a causa aparecer — que é o defeito 2. Registro aqui
para ninguém refazer esse caminho.

O que eu medi

typecheck 0
lint (arquivos tocados) 0
casos novos 15, todos verdes
suíte inteira 5 arquivos / 7 casos vermelhos — idênticos aos da main sem este PR

Sabotagem, previsto × medido — cada conserto desfeito sozinho, um por vez,
com restauração conferida em passo separado:

sabotagem previsto medido
sugestaoParaMostrar volta a devolver a mais recente 3 vermelhos, controles verdes ✅ exatamente 3
} catch { sem nome volta 2 vermelhos (a cerca e o registro) ✅ exatamente 2

Os cinco vermelhos são de ambiente desta máquina (resolução do pdfjs-dist no
Windows) e estão medidos nos dois lados. Uma primeira rodada trouxe três
arquivos a mais; rodados sozinhos, os três passam, e a segunda rodada da suíte
inteira voltou aos mesmos cinco — instabilidade da máquina, registrada aqui em
vez de omitida.

Os controles positivos ficaram verdes nas duas: a sugestão que espera revisão
continua aparecendo, e as três frases de erro continuam distintas. Sem eles,
uma implementação que escondesse tudo — ou que devolvesse sempre o genérico —
passaria por metade dos casos sem conservar nada.

O que eu NÃO medi

  • Não rodei Playwright. Não há prova de tela deste PR. Os dois consertos são
    visíveis, e merecem ser conferidos por quem revisar.
  • Não reproduzi a causa raiz do erro original. Ela continua desconhecida — é
    justamente o que o defeito 2 impedia de saber. O que este PR garante é que a
    próxima ocorrência diga qual foi.
  • Não mexi em generateReplyDraft. As duas exceções que ela lança já
    existiam; só pararam de ser descartadas.

Checklist (Definition of Done)

  • pnpm typecheck zerado
  • pnpm lint zerado
  • Testes relevantes existem e passam (pnpm test:unit)
  • RLS testada — não se aplica: nenhuma tabela nova, nenhuma policy tocada
  • Audit log — não se aplica: o caminho de sucesso já auditava e não mudou; o de erro não é mutação
  • Zod valida todo input externo novo — não há input novo; o POST segue sem corpo
  • Sem console.log esquecido
  • Mudança de schema — não há
  • Doc de contrato — não muda contrato: os códigos de erro ficaram mais específicos (reply_no_agent, reply_context_unavailable) e o antigo reply_unavailable continua sendo o genérico

Fragmento em .changes/ incluído.

🤖 Generated with Claude Code

…sai da tela

Dois defeitos medidos numa instalacao real em 2026-09-12.

1) A REJEITADA NAO SAIA DA TELA

O painel pedia as cinco ultimas sugestoes (`order by created_at desc limit 5`)
e mostrava a primeira SEM olhar o estado dela. Rejeitar nao fecha nada: a
rejeitada continua sendo a mais recente, entao o texto morto ficava na tela,
com a caixa desabilitada e sem botao de fechar — nao existe nenhum no
componente.

O caso que travou de vez: quem rejeita costuma pedir outra em seguida. Se essa
geracao falha, nada substitui a rejeitada e a tela fica presa. Foi exatamente o
que aconteceu.

Escolha deliberada: olhar SO a mais recente. Procurar na lista a primeira que
ainda sirva ressuscitaria uma sugestao antiga logo depois de a atual ser
rejeitada — um texto que o atendente acabou de recusar voltando sozinho.

`failed` continua aparecendo: a frase dela e a unica pista que sobra.

E a confirmacao da rejeicao estava amarrada a `draft` existir. Sem ajustar
isso, o conserto faria o aviso sumir junto com a sugestao, e o clique em
Rejeitar apenas esvaziaria a tela em silencio.

2) O ERRO NAO DIZIA NADA, E O IDENTIFICADOR NAO LEVAVA A NADA

A rota fazia `} catch {` — SEM NOME. A causa morria ali. Tres situacoes sem
nada em comum viravam a mesma frase, que mandava conferir a publicacao do
agente mesmo quando o problema era o provedor de IA fora do ar.

E nada era registrado — nem logger, nem Sentry — enquanto a tela exibia o
requestId, o que faz a mensagem PARECER rastreavel. Um numero que promete e nao
entrega manda a pessoa procurar onde nao ha o que achar.

Agora `motivoDaFalha` nomeia as duas causas que `generateReplyDraft` lanca de
proposito, o resto admite que e outra coisa, e o motivo vai para o
`logger.error` com org, conversa e requestId.

MEDIDO E DESCARTADO: a hipotese de que a falha vinha de enviar conteudo vazio
nao se sustenta. Os tres caminhos ja validavam — o composer barra em
`Composer.tsx:111` e `:344`, o "Aprovar e enviar" em `!body.trim()`, e o
"Sugerir resposta" nao tem campo nenhum. Nao ha validacao faltando; ha causa
escondida, que e o defeito 2.

Regras puras em `lib/agent-engine/agent/sugestao-de-resposta.ts` para poderem
ser medidas fora da tela, com cerca de forma contra o `catch` sem nome voltar.

Co-Authored-By: Claude Opus 5 <[email protected]>
@vercel

vercel Bot commented Sep 12, 2026

Copy link
Copy Markdown

@paulolimajr77 is attempting to deploy a commit to the rafael-maudibrasil's projects Team on Vercel.

A member of the Team first needs to authorize it.

@ecc-tools

ecc-tools Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

ECC Tools / Security Evidence

Commit: 927f5aadb6a67bd820775adeedd9c0415e70f60e

Security scanner evidence required (action_required)

Detected 1 security-sensitive predictive risk signal(s) without scanner evidence.

Mode: enforce

Findings:

  • Security-sensitive changes may ship without scanner evidence: The PR touches billing, secrets, auth, webhooks, agent, or CI-sensitive surfaces without adding obvious security scanner, code scanning, or security-focused validation evidence. (1 security-sensitive paths changed; 0 security scanner or security-focused validation artifacts changed)

Touched security-sensitive paths:

  • lib/agent-engine/agent/sugestao-de-resposta.ts

Expected evidence:

  • Security scanner, code scanning, secret scanning, dependency/security review, or focused security regression output.
  • SARIF/code-scanning upload or equivalent pass/fail gate for the changed surface.

Check publication was denied or unavailable. An app owner must enable Checks: read and write, and the installation owner must approve the updated permission.

@ecc-tools

ecc-tools Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

ECC Tools / PR Risk Taxonomy

Commit: 927f5aadb6a67bd820775adeedd9c0415e70f60e

PR taxonomy review recommended (neutral)

Detected 2 PR taxonomy bucket(s): Security Evidence, CI/CD Recommendation.

Scanned 6 changed file(s).

Roadmap taxonomy buckets:

Security Evidence

Security-sensitive changes should carry explicit scanner, code-scanning, or focused regression evidence.

Signals:

  • Security-sensitive changes may ship without scanner evidence
  • 0 security-sensitive path(s) changed

Paths:

  • .changes/sugestao-diz-o-motivo-e-solta-a-tela.md
  • app/api/v1/conversations/[id]/draft-reply/route.ts
  • components/inbox/composer/ReplyReviewPanel.tsx

CI/CD Recommendation

CI, dependency, coverage, and contract signals should be routed into follow-up checks or verification work.

Signals:

  • API contract changes may ship without integration coverage
  • API implementation changes may ship without contract artifact updates
  • User-facing UI changes may ship without browser coverage
  • 1 CI or workflow path(s) changed

Paths:

  • tests/unit/sugestao-de-resposta.test.ts
  • app/api/v1/conversations/[id]/draft-reply/route.ts
  • components/inbox/composer/ReplyReviewPanel.tsx
  • lib/agent-engine/agent/sugestao-de-resposta.ts
  • lib/i18n/dicionario.ts

Check publication was denied or unavailable. An app owner must enable Checks: read and write, and the installation owner must approve the updated permission.

@ecc-tools

ecc-tools Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

ECC Tools / Reference Set Readiness

Commit: 927f5aadb6a67bd820775adeedd9c0415e70f60e

Reference set readiness gaps detected (neutral)

Reference evidence present for 0/7 areas (0%) across 6 changed file(s).

This check is based on files changed in this PR. Repository-level readiness is still reported by /ecc-tools analyze comments and generated manifests.

Area Status Evidence / Next Step
Deep analyzer corpus Missing Add analyzer fixture, golden, benchmark, or reference-set files that can catch analyzer regressions.
RAG/evaluator comparison Missing Add retrieval or evaluator reference-set comparison fixtures with expected ranking behavior.
PR salvage/review corpus Missing Add stale-PR, review-thread, reopen-flow, or salvage reference cases for queue cleanup automation.
Discussion triage corpus Missing Add public discussion triage fixtures, golden cases, or reference sets for informational, answered, and no-response classifications.
Harness compatibility Missing Add cross-harness, adapter-compliance, or harness-audit evidence for Claude, Codex, OpenCode, Zed, dmux, and agent surfaces.
Security evidence Missing Attach security evidence such as SBOMs, SARIF, audit reports, or AgentShield evidence packs.
CI failure-mode evidence Missing Add captured CI failure logs, dry-run fixtures, or troubleshooting docs for common workflow failure modes.

Check publication was denied or unavailable. An app owner must enable Checks: read and write, and the installation owner must approve the updated permission.

@ecc-tools

ecc-tools Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

ECC Tools / Hosted Promotion Readiness

Commit: 927f5aadb6a67bd820775adeedd9c0415e70f60e

Hosted promotion readiness passed (success)

No hosted promotion evidence gaps detected across 6 changed file(s); 0 corpus scenarios had matching evidence.

This check compares PR file changes against the evaluator/RAG promotion corpus in src/analyzers/fixtures/evaluator-rag-corpus.ts.
Hosted output scoring inspected 0 completed cached hosted job results.

No evaluator corpus scenarios matched this PR.

Check publication was denied or unavailable. An app owner must enable Checks: read and write, and the installation owner must approve the updated permission.

@github-actions

Copy link
Copy Markdown

Recebido, @paulolimajr77 — obrigado por isto.

Duas coisas que vão parecer erro seu e não são:

  • O check Vercel vermelho ("Authorization required to deploy") é esperado em PR de fork. A
    main faz deploy de produção e a Vercel se recusa a construir código de fora, o que está
    certo. Ele não entra no gate de merge.
  • No primeiro PR de quem nunca contribuiu aqui, os workflows ficam parados esperando
    liberação
    — política do GitHub, não sua. Enquanto isso o PR parece não ter check nenhum
    (nem o gh pr checks mostra os que estão nesse estado). Quem tria libera; você não precisa
    fazer nada.

Um mantenedor vai revisar de verdade — rodando os gates e reproduzindo o comportamento, não só
lendo o diff — e responde aqui em até um dia útil, com a medição junto, nunca com um "acho
que".

Esta mensagem é automática e não diz nada sobre o seu PR: ela é sobre o processo. O que vem
depois é pessoa.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant