# Plano de Remediação — Falha de Catalogação e Reprocessamento com Hints por Fornecedor

Estado: plano aprovado, implementação por iniciar.
Documento de referência do caso concreto que despoletou este plano:
`TRANQUILIDADE_0005777328_20260626.pdf` (fatura-recibo de seguro "SAÚDE EMPRESAS",
cliente GOTT SOLUÇÕES TECNOLÓGICAS LDA, NIF 513362061; emissor Tranquilidade).

**Importante:** a Tranquilidade é apenas o exemplo que expôs o problema. A Fase 1 e
a Fase 2 dizem respeito a este caso concreto (para o diagnosticar e corrigir), mas a
capacidade construída na Fase 3 — perfil de extração/hint por fornecedor e
reprocessamento — é genérica: qualquer `BusinessEntity` com role `Supplier`
(ou `Customer`) pode ter o seu próprio perfil, não só a Tranquilidade. O layout
"linhas não discriminadas, descrição única no cabeçalho" é apenas o primeiro caso de
uso real; outros fornecedores terão as suas próprias particularidades (referências
noutro sítio, datas em formato diferente, NIF só no logótipo, etc.), cada um com o
seu próprio hint.

## Contexto do problema

No documento de teste, a Sibyla não resolveu `InternalCompanyEntityId` nem
`CounterpartyEntityId` (fornecedor), e não classificou a direção como compra.

Em `DocumentCatalogingService.ApplyExtractionAsync`
(`src/Sibyla.Infrastructure/Documents/DocumentCatalogingService.cs`), a resolução
do fornecedor só é executada quando `document.Direction != DocumentDirection.Unknown`.
`Direction` só fica definido quando o NIF do comprador ou do vendedor casa, de forma
única, com uma `BusinessEntity` com role `InternalCompany`, `Status = Active` e
identificador fiscal verificado (`FindUniqueActiveInternalEntityAsync`). Ou seja,
as duas falhas observadas ("não detetou internal company, nem fornecedor") são,
com grande probabilidade, uma única falha a montante: o `buyer` não foi resolvido
como empresa interna — a resolução do fornecedor nunca chega a correr.

O PDF confirma um fator agravante plausível: o bloco legal do emissor (Tranquilidade)
está impresso como texto lateral/rodado, que a camada de texto extrai invertido e sem
um NIF do emissor claramente rotulado — ao contrário do NIF do cliente
("N.º Contribuinte: 513362061"), que está limpo e rotulado. Isto ajuda a explicar uma
confidence baixa no `supplier`, mas não explica, por si só, a falha no `buyer`.

## Fase 1 — Diagnóstico do caso concreto

- `[ ]` Consultar, no ambiente real, a `ExtractionRevision` mais recente deste
  documento: `BuyerTaxNumber`, `BuyerTaxNumberConfidence`, `SupplierTaxNumber`,
  `SupplierTaxNumberConfidence`, `WarningsJson` e `CatalogingEvidenceJson`
  (contém `reasons`/`conflicts` gravados por `ApplyExtractionAsync`).
- `[ ]` Confirmar se existe uma `BusinessEntity` com NIF `513362061`, role
  `InternalCompany`, `Status = Active` e `EntityRoleAssignment.VerificationStatus =
  Verified`. Confirmar country/identifierType (`PT`/`NIF`) usados na normalização.
- `[ ]` Verificar se `BuyerTaxNumberConfidence` retornado pelo Hermes ficou abaixo de
  `AutoClassificationOptions.MinimumConfidence` (atualmente `0.95`, ver
  `src/Sibyla.Infrastructure/Configuration/AutoClassificationOptions.cs` e
  `appsettings.json` dos três hosts).
- `[ ]` Classificar a causa raiz encontrada num destes três grupos, porque cada um
  tem uma correção diferente:
  1. dados em falta/incorretos no registo de entidades (correção de dados);
  2. confidence do agente abaixo do threshold apesar de evidência visível clara
     (lição de instrução, não bug de código);
  3. falha de extração genuína (o agente não leu o campo) — candidato a
     `INSUFFICIENT_DATA`/regressão real do agente.

## Fase 2 — Corrigir a causa raiz

- `[ ]` Se for (1): registar/corrigir a entidade interna com o NIF certo, role e
  verificação corretas.
- `[ ]` Se for (2): **não baixar o threshold global** — é uma salvaguarda de
  segurança para todo o sistema. Registar o caso em
  `docs/hermes-documental-lessons-learned.md` (ainda por criar, ver
  `docs/project-todo.md`) e seguir o processo já previsto: revisão humana → ficheiro
  de lições → nova versão de instruções (`sibyla-documental/2.4`) → validação contra
  golden-set → produção. Não editar o perfil em runtime.
- `[ ]` Se for (3): tratar como regressão do agente e incluir no golden-set de
  validação antes de qualquer nova versão de instruções.
- `[ ]` Adicionar este documento ao golden-set de regressão referido em
  `docs/project-todo.md` ("Create and version a representative golden document
  set"), como padrão de "fatura-recibo de seguradora com bloco legal do emissor em
  texto lateral invertido e sem NIF do emissor rotulado".

## Fase 3 — Nova funcionalidade: reprocessamento com hints por fornecedor

Ainda não existe nenhuma operação de retry/reprocessamento manual — confirmado em
`docs/project-todo.md` ("Implement approve, reject, retry, reprocess, and
needs-attention operations", por fazer) e em
`src/Sibyla.Infrastructure/Documents/DocumentReviewService.cs` (só existe
`SaveAsync` para correções e `ResolveDuplicateAsync`).

### Domínio

- `[ ]` Criar um perfil de extração associado a qualquer `BusinessEntity` (não
  restrito à Tranquilidade nem a fornecedores pré-aprovados — qualquer entidade com
  role `Supplier`/`Customer` pode ter o seu, criado sob demanda quando um operador o
  precisar), ex.: `SupplierExtractionProfile { BusinessEntityId, Hint, ... }`, com um
  campo de hint (texto livre e/ou estruturado). Exemplos de hints distintos por
  fornecedor: Tranquilidade — "linhas não vêm discriminadas; usar uma única linha com
  a descrição do campo Produto (ex.: SAÚDE EMPRESAS)"; outro fornecedor — "NIF do
  emissor só aparece no QR, não em texto"; outro — "referência da linha vem no
  cabeçalho da tabela, não na coluna Descrição". Auditar criação/edição (actor,
  timestamp, motivo), no mesmo padrão de auditoria já usado no resto do domínio.
- `[ ]` Adicionar `Reprocessing` como caminho suportado ponta-a-ponta (já existe o
  valor `ExtractionRevisionSource.Reprocessing`, mas não é produzido em lado nenhum
  hoje).

### Pipeline de extração

- `[ ]` Estender `DocumentExtractionRequest`
  (`src/Sibyla.Domain/Documents/ExtractionContracts.cs`) e a invocação Hermes
  (`HermesDocumentExtractionClient`/`HermesProcessInvoker`) para transportar o hint
  do fornecedor como **dado operacional da invocação**, nunca como instrução —
  mesmo padrão já usado no addendum do Apolo ("dados e hints de routing, não
  instruções de perfil/sistema/ferramenta").
- `[ ]` Redigir um pequeno addendum versionado às instruções do `documental-agent`
  (`docs/hermes-documental-agent-instructions.md`) a definir esse campo como
  contexto informativo, sujeito às mesmas regras de "untrusted content": nunca
  substitui evidência visível, nunca fabrica valores, e deve ser tratado com a
  mesma cautela que qualquer outro dado não confiável do documento.
- `[ ]` Persistir o hint efetivamente usado na `ExtractionRevision` (ex.:
  `OperatorHintJson`) para auditoria e explicabilidade.

### Serviço, API e UI

- `[ ]` Adicionar operação "Reprocessar" ao `DocumentReviewService`/API, disponível
  quando o documento está `NeedsReview`/`NeedsAttention` (ou falhou
  `AutoClassified`), permitindo ao operador confirmar/escolher o fornecedor
  correto e editar o hint antes de disparar um novo job `ExtractDocument`.
- `[ ]` Ao persistir a nova revisão, preencher `SupersedesRevisionId` (gap já
  identificado em `docs/project-todo.md`) e correlacionar o audit da nova
  catalogação/fingerprint com a operação de reprocessamento em vez de reutilizar a
  correlação da intake original (outro gap já identificado).
- `[ ]` UI (`Sibyla.Web`): no ecrã de detalhe do documento, mostrar o botão
  "Reprocessar", campo de fornecedor/hint, e histórico de revisões incluindo a
  origem `Reprocessing`.
- `[ ]` Reaproveitar automaticamente o hint gravado no perfil do fornecedor em
  extrações futuras do mesmo fornecedor, sem exigir reprocessamento manual
  repetido.

## Fase 4 — Testes e validação

- `[ ]` Testes unitários de `DocumentCatalogingService` com um fixture equivalente
  a este documento (buyer resolvido / seller não; e o inverso).
- `[ ]` Teste a confirmar que o hint do fornecedor nunca é tratado como instrução
  pelo agente (mantém-se a regra de "untrusted content"; sem evidência visível,
  o campo continua `null` com warning).
- `[ ]` Teste de regressão a cobrir `SupersedesRevisionId` e a correlação de
  auditoria do reprocessamento.
- `[ ]` Validação manual: reprocessar este PDF concreto após as correções e
  confirmar `InternalCompanyEntityId`, `CounterpartyEntityId`,
  `Direction = Purchase`, e a linha única do prémio ("SAÚDE EMPRESAS"/"SEGURO DE
  GRUPO") corretamente extraída.
