# Dossie de paridade PROFUNDO — DICT claims (portabilidade / posse)

Auditor: engenharia PIX (read-only). Zero inferencia: cada afirmacao com prova (arquivo:linha ou tabela.coluna).
Escopo: reivindicacoes DICT (OWNERSHIP=posse, PORTABILITY=portabilidade) — maquina de estados, prazos,
automacao de quarentena, papel doador/reivindicador, validacoes, transicoes.

Fontes:
- LEGADO decompilado: `.scratch/legado-pix-decompiled/DICT.Core.Worker.Claims.decompiled.cs`,
  `DICT.Core.Application.decompiled.cs`, `DICT.Core.Infrastructure.decompiled.cs`, `DICT.Core.General.decompiled.cs`.
- LEGADO DB vivo: SQL Server `des_4dict` (TB_PARAMETRO, TB_TIPOSITUACAO, TB_TIPOREIVINDICACAO,
  TB_TIPOMOTIVOREIVINDICACAO, TB_OPERACAOREIVINDICACAO).
- NOSSO: `pix/backend/apps/dict_service/lib/dict_service/claims.ex`,
  `claims/entry_claim.ex`, `nats/claim_deadline_consumer.ex`, `sync/inbound_sync.ex`,
  `workers/dict_inbound_poll_worker.ex`, `ownership.ex`,
  `apps/shared/lib/shared/bacen/dict_client.ex`, `apps/shared/lib/shared/bacen/dict/response_parser.ex`.

---

## 1. Arquitetura da automacao

### 1.1 LEGADO — worker unico multi-fase

`DICT.Core.Worker.Claims` registra SO um hosted service: `WorkerBuscaSolicitacao`
(`DICT.Core.Worker.Claims.decompiled.cs:73`). O laco `ExecuteAsync` (linha 137) roda, em cada ciclo e em
ordem fixa, 5 fases + 2 condicionais:

1. `BuscaSolicitacaoDoacaoChave` -> `BuscaSolicitacaoNaoIntegradaUseCase.Processar`
   (Worker.Claims:145; impl `DICT.Core.Application.decompiled.cs:1584`): equaliza com o BACEN em 3 sub-fases:
   - `EqualizaSolicitacaoAbertaDoador` (App:1600): `ListaReivindicacoes(IsDonor=true, [WAITING_RESOLUTION])`.
   - `EqualizaSolicitacaoReinvidicador` (App:1627): `ListaReivindicacoes(IsClaimer=true, [OPEN, WAITING_RESOLUTION])`.
   - `EqualizaSolicitacaoConcluida` (App:1658): `ListaReivindicacoes(IsClaimer=true, [COMPLETED])` -> `ConcluiReivindicacaoBase`.
2. `AtualizaSolicitacaoCancelada` (Worker.Claims:161; impl App:5962): `ListaReivindicacoes([CANCELLED])` -> grava CANCELLED local.
3. `AtualizaSolicitacaoConfirmada` (Worker.Claims:177; impl App:6200): `ListaReivindicacoes(IsClaimer=true, [CONFIRMED])`;
   se PORTABILITY (ou OWNERSHIP USER_REQUESTED com flag) -> `ConcluiReivindicacaoChave`; enfileira conclusao.
4. `AtualizaQuarentenaPrimeiraEtapa (Posse)` (Worker.Claims:193; impl App:1357): fim do periodo de resolucao do DOADOR.
5. `AtualizaQuarentenaPortabilidade` (Worker.Claims:209; impl App:1298): fim do periodo de resolucao do DOADOR (portabilidade).

Condicionais por flag (`DICTConfig`):
- `ExecutaWorkerConcluiReivindicacaoPosseAutomatico` (Worker.Claims:223) -> `ConcluiReivindicacaoPosseAutomaticoUseCase` (App:1924).
- `ExecutaWorkerCancelamentoPosse30Dias` (Worker.Claims:242) -> `CancelaReivindicacaoPosseAutomaticoUseCase` (App:1790).

Delay do laco: `NR_QtSegundosVerificacaoReivindicacoes * 1000` (Worker.Claims:261).

### 1.2 NOSSO — polling incremental + timers durAveis JetStream

Duas metades:
- **Equalizacao inbound** (espelho das fases 1-3 do legado): `DictService.Workers.DictInboundPollWorker`
  (cron Oban, `dict_inbound_poll_worker.ex:34-55`) roda 4 pernas, entre elas `:claims_donor` e `:claims_claimer`
  (`inbound_sync.ex:74`), que chamam `Claims.sync_inbound_claims_from_bacen(IsDonor|IsClaimer)`
  (`inbound_sync.ex:244-248`) com watermark persistido em `monetarie_dict.dict_sync_cursors` (incremental, overlap 5min,
  paginacao +1s como o legado — `inbound_sync.ex:9-24,64-69,205-216`).
- **Auto-resolucao de prazo** (espelho das fases 4-5 + condicionais): `create_claim` agenda 3 timers durAveis
  (`claims.ex:1668-1689`), consumidos por `DictService.Nats.ClaimDeadlineConsumer` (`claim_deadline_consumer.ex`),
  que chama `auto_resolve_on_donor_timeout/1` e `auto_resolve_on_claimer_timeout/1`.

Divergencia estrutural (nao e defeito): legado = worker de varredura de banco por polling; nosso = timer durAvel
JetStream (`Nats-Msg-Deliver-After`, gotcha #17) + poll incremental. Os desfechos convergem (ver secao 4).

---

## 2. Maquina de estados

### 2.1 LEGADO — `TB_TIPOSITUACAO` (des_4dict, vivo)

| Id | Codigo | Descricao |
|----|--------|-----------|
| 1 | OPEN | Aberta |
| 2 | WAITING_RESOLUTION | Aguardando |
| 3 | CONFIRMED | Confirmada |
| 4 | CANCELLED | Cancelada |
| 5 | COMPLETED | Completada |
| 101 | WAITING_VALIDATION | Aguard Valida Posse (estado LOCAL de posse) |
| 102 | KEY_INCLUDED | Chave incluida Local (estado LOCAL) |

Tipos (`TB_TIPOREIVINDICACAO`): 1 OWNERSHIP (Posse), 2 PORTABILITY (Portabilidade).
Motivos (`TB_TIPOMOTIVOREIVINDICACAO`): 1 USER_REQUESTED, 2 ACCOUNT_CLOSURE, 3 FRAUD, 4 DEFAULT_OPERATION, 5 RECONCILIATION.
Acervo vivo: `TB_OPERACAOREIVINDICACAO` = 343 linhas (feature exercitada).

Transicoes reais no codigo:
- Abertura -> OPEN (`Infrastructure:6033` `TpSituacao = enumTipoSituacao.OPEN` em `AdicionarOperacaoReivindicacao`).
- Confirmacao (doador) -> CONFIRMED (`Infrastructure:4368`).
- Cancelamento -> CANCELLED (`Infrastructure:4556`).
- Conclusao (reivindicador) -> COMPLETED (`Infrastructure:4778` em `ConcluiReivindicacaoBase`).

### 2.2 NOSSO — `EntryClaim`

`claims.ex:33` `@claim_statuses ~w(OPEN WAITING_RESOLUTION CONFIRMED CANCELLED COMPLETED)`.
Grafo de transicao validado no schema (`claims/entry_claim.ex:151-161`):
```
OPEN               -> WAITING_RESOLUTION | CONFIRMED | CANCELLED
WAITING_RESOLUTION -> CONFIRMED | COMPLETED | CANCELLED
CONFIRMED          -> COMPLETED | CANCELLED
CANCELLED/COMPLETED-> (terminal)
```
Os 5 estados BACEN estao cobertos e as transicoes espelham o legado. Os estados LOCAIS 101/102
(WAITING_VALIDATION/KEY_INCLUDED) NAO existem como status da claim; o conceito de "posse validada" foi
reimplementado num dominio separado (`DictService.Ownership`, validacao OTP scope CLAIM — ver g8/coberto c8),
gate antes de `complete_claim` (`claims.ex:234`).

---

## 3. Prazos (quarentena)

### 3.1 LEGADO — prazos vem do BACEN, worker so detecta o vencimento

O legado NAO calcula prazo localmente: persiste `ResolutionPeriodEnd`/`CompletionPeriodEnd` da resposta do BACEN
(`Infrastructure:6038-6039` `DataFimPeriodoConclusao = retornoBacen.Claim.CompletionPeriodEnd`,
`DataFimPerodoResolucao = retornoBacen.Claim.ResolutionPeriodEnd`). O worker so consulta o banco por vencimento:
- Fim da resolucao do DOADOR: `ListOperacaoResolucaoExpirada` (`Infrastructure:8735`) filtra
  `b.DataFimPerodoResolucao < now && DataCancelamento==null && DataConfirmacao==null && d.ContaAtiva`.
- Fim da conclusao do REIVINDICADOR (posse): `ListOperacaoReivindicacaoPosseFinalizar` (`Infrastructure:8785`)
  filtra `b.DataFimPeriodoConclusao < now && IdTipoSituacao==3 (CONFIRMED)`.
- Cancelamento posse aos 30 dias: `ListOperacaoReivindicacaoPosse30diasFinalizar` (`Infrastructure:8831`)
  filtra `b.DataFimPerodoResolucao.AddDays(23) <= now && IdTipoSituacao in (1,2,3)` — ou seja, 7d de resolucao + 23 = 30 dias.

Parametros de tempo (des_4dict.TB_PARAMETRO, vivo — valores do snapshot DEV; os defaults de PRD sao maiores):
`NR_QtSegundosQuarentaPosse=20`, `NR_QtSegundosVerificacaoReivindicacoes=20`, `NR_QtLimiteContasPF=5`,
`NR_QtLimiteContasPJ=20`, `NR_QtLimitReivindicacoes=100`. (O contexto 08-dict-med.md registra o default de codigo
`NR_QtSegundosQuarentaPosse=604800`=7 dias.) O prazo REAL da claim (7d resolucao / 30d conclusao) e sempre o do
BACEN persistido, nunca os segundos do worker (que sao so o intervalo de VARREDURA).

### 3.2 NOSSO — prazos HARDCODED no create; do BACEN so no sync inbound

`claims.ex:45-47`:
```
@donor_deadline_days 14
@claimer_deadline_days 30
@donor_notification_days 7
```
No `create_claim` (nos = reivindicador), os prazos sao calculados LOCALMENTE:
`donor_deadline = now + 14d`, `claimer_deadline = now + 30d` (`claims.ex:105-106,1628-1630`).
O `create_claim_via_bacen` extrai da resposta do BACEN SOMENTE o `claim_id` (`claims.ex:990-993`), e NAO usa
`resolution_period_end`/`completion_period_end` — que o parser JA devolve (`response_parser.ex:60-61,235-236`).
Prova negativa: `grep resolution_period_end|completion_period_end claims.ex` nao encontra uso vindo da resposta do
create. Ver GAP g1.

No caminho INBOUND (sync), os prazos SAO os do BACEN: `inbound_claim_attrs` mapeia
`resolution_period_end <- resolutionPeriodEnd` e `claimer_deadline <- completionPeriodEnd`
(`claims.ex:688-692`), e `schedule_synced_claim_deadlines` agenda `donor_timeout_at = resolution_period_end`
(`claims.ex:1707`) e claimer_timeout em `claimer_deadline` (`claims.ex:1730-1735`).

---

## 4. Automacao de quarentena — desfechos por papel/tipo

### 4.1 Fim da resolucao (timer do DOADOR)

**LEGADO:**
- OWNERSHIP: `AtualizaQuarentenaPrimeiraEtapaUseCase.Processar` -> `ConfirmaReivindicacao(..., DEFAULT_OPERATION)`
  (`App:1397`) sobre `ListOperacaoResolucaoExpirada(doacao:true, OWNERSHIP)` (`App:1440`). Doador CONFIRMA no vencimento.
- PORTABILITY: `AtualizaQuarentenaPortabilidadeUseCase.Processar` -> `CancelaReivindicacao(..., DEFAULT_OPERATION, doacao:true)`
  (`App:1330`) sobre `ListOperacaoResolucaoExpirada(doacao:true, PORTABILITY)` (`App:1347`). Doador CANCELA no vencimento.

**NOSSO:** `auto_resolve_on_donor_timeout/1` (`claims.ex:778-790`):
- `%{claim_type: "PORTABILITY"}` -> `auto_cancel_portability_on_donor_timeout` (`claims.ex:792`) — CANCELLED/DONOR_CANCELLED.
- default (OWNERSHIP) -> `auto_confirm_on_donor_timeout` (`claims.ex:785,892`) — CONFIRMED/DONOR_TIMEOUT.
Paridade de desfecho por tipo: **COBERTO** (comentarios citam os UseCases exatos, `claims.ex:772-776`).

### 4.2 Fim da conclusao (timer do REIVINDICADOR)

**LEGADO:**
- `ConcluiReivindicacaoPosseAutomaticoUseCase.Processar` -> `ConcluiReivindicacaoPosse` (`App:1965`) sobre
  `BuscaFinalizaReivindicacaoPosseAutomatico` = `ListOperacaoReivindicacaoPosseFinalizar(doacao:false, CONFIRMED, OWNERSHIP)`.
  Reivindicador CONCLUI (COMPLETED).
- `CancelaReivindicacaoPosseAutomaticoUseCase.Processar` -> `CancelaReivindicacao(doacao:false)` sobre a posse de 30 dias;
  se o BACEN responde "Current claim status('COMPLETED')..." cai em `ConcluiReivindicacao` (`App:1835-1838`).

**NOSSO:** `auto_resolve_on_claimer_timeout/1` (`claims.ex:841-865`):
- OWNERSHIP CONFIRMED onde `claimer_ispb == own` -> `auto_complete_claim` (COMPLETED); se falha, cai em
  `auto_cancel_on_claimer_timeout` (`claims.ex:845-857`) — espelha a reconciliacao do CancelaReivindicacaoPosseAutomatico.
- demais -> `auto_cancel_on_claimer_timeout` (`claims.ex:859-860,933`). **COBERTO.**

### 4.3 Consumo dos timers

`ClaimDeadlineConsumer.route` (`claim_deadline_consumer.ex:53-70`): `CLAIM_DONOR_TIMEOUT`->donor, `CLAIM_CLAIMER_TIMEOUT`->claimer,
`CLAIM_DONOR_NOTIFICATION`->log D+7 (so visibilidade). Guards de status tornam o timer idempotente
(`claim_deadline_consumer.ex:95-101`). **COBERTO.**

---

## 5. Abertura da claim (ReivindicaChave)

**LEGADO** `FactoryUnitOfWorkInclusao.ReivindicaChave` (`Infrastructure:5918`):
1. `Valida` (secao 6) + `ValidarNrSPBParticipanteLogado` + `ValidaHorario(Reivindicar)` (`Infrastructure:5920-5935`).
2. Portabilidade: se a chave EXISTE na base local com o MESMO ISPB -> erro "Nao e possivel realizar portabilidade
   de chave para mesma IF" (`Infrastructure:5937-5944`).
3. Monta `CreateClaimRequest` (Type, Key, KeyType, ClaimerAccount, Claimer) (`Infrastructure:6052-6068`), assina XMLDSig,
   `Send(GrupoMetodoClaim)`. Sucesso -> OperacaoReivindicacao OPEN com `DataFimPeriodoConclusao=CompletionPeriodEnd`,
   `DataFimPerodoResolucao=ResolutionPeriodEnd`, `TpMotivoReinvidicacao=USER_REQUESTED` (`Infrastructure:6026-6049`).
   Falha -> `InclusaoRejeitadaPeloBACEN` + traduz Problem (EntryBlocked/TaxIdNumberBlocked = ordem judicial).

**NOSSO** `create_claim/1` (`claims.ex:80-114`):
1. `Keys.get_entry` + `check_entry_can_be_claimed` (ACTIVE, `claims.ex:1550`) + `check_claimer_not_donor`
   (claimer_ispb != entry.ispb, `claims.ex:1553`) + `check_no_pending_claim` (`claims.ex:1556`).
2. `determine_claim_type` (documento igual = PORTABILITY, senao OWNERSHIP, `claims.ex:1614-1620`).
3. `:bacen` -> `create_claim_via_bacen` (monta payload `bacen_create_claim_payload`, `claims.ex:1387-1407`;
   assina/envia via `DictClient.create_claim`, `dict_client.ex:392`). Insere claim OPEN + publica
   `monetarie.dict.claims.initiated` + agenda 3 timers (`claims.ex:1042-1076,1668`).

Cobertura: a mecanica de abertura, o `CreateClaimRequest` assinado e o mirror OPEN estao **cobertos**. Diferencas em
validacao: g4 (EVP / OWNERSHIP em CPF-CNPJ), e o gate de horario g6 (secao 7).

---

## 6. Validacoes de dados

**LEGADO** `ValidaReivindicaChaveUseCase.ValidaDados` (`App:1110-1128`) roda uma bateria via `Validacoes`
(`General:8422+`):
- `ValidaTipoChave`, `ValidaChave` (formato + tamanho<=77, `General:8671-8693`), `ValidaTipoPessoa`,
  `ValidaCpfCnpjPessoa` (CPF/CNPJ valido, `General:8695`), `ValidaConta` (<=20, `General:8737`),
  `ValidaAgencia` (<=4, `General:8729`), `ValidaSPB`, `ValidarCPFCNPJ` (chave CPF/CNPJ = documento, `General:8647-8652`),
  `ValidarNome`, `ValidarDataAberturaConta` (obrigatoria, `General:8639-8644`).
- `ValidaTipoEVP` (`App:1138-1144`): EVP NAO pode reivindicar (portabilidade/posse) -> `TipoEVPNReivindica`.
- `ValidaPermissao` (`App:1130-1136`): CPF/CNPJ + OWNERSHIP -> `PermissaoNegadaCPJCNPJ` "Nao e permitido reivindicar posse para CPF/CNPJ".

**NOSSO** `create_claim` (`claims.ex:80-114`): valida SOMENTE entry ativo, claimer!=donor, sem claim pendente.
Formato/documento/data-abertura sao delegados ao changeset (`entry_claim.ex:77-87`, valida claim_type/key_type/status/ISPB)
e ao BACEN (`:bacen` mode rejeita). NAO ha equivalente local a `ValidaTipoEVP` nem `ValidaPermissao` (ver g4).

---

## 7. Gate de horario (janela do participante)

**LEGADO:** toda operacao de claim gata por janela do participante:
`ValidaHorario(enumTipoOperacao.Reivindicar|Doar, tpChave, nrSpbParticipante)` em abrir (`Infrastructure:5931`),
confirmar (`4329`), cancelar (`4507`), concluir posse (`4693`) e concluir portabilidade (`4825`).

**NOSSO:** nenhum gate de janela de horario nas operacoes de claim (`claims.ex` create/confirm/cancel/complete nao
chamam nada equivalente). Ver g6.

---

## 8. Equalizacao inbound e materializacao

**LEGADO** `CarregarNaoIntegradas` (`Infrastructure:6755`): idempotente por
`GetByIdReinvidicacaoSimples(idReivindicacaoBacen, ISPB, doacao)` (`:6758`); grava OperacaoReivindicacao com o status
REAL do BACEN (`:6866`). Regra ANTIFRAUDE crucial (`Infrastructure:6791-6804`): se somos DOADOR e a claim esta
OPEN/WAITING_RESOLUTION e (a chave local nao existe OU e PORTABILITY com documento diferente do titular local) ->
`CancelaReivindicacao` automatico com motivo FRAUD (portabilidade) ou DEFAULT_OPERATION (posse).

**NOSSO** `materialize_inbound_claim` (`claims.ex:548-608`): idempotente por `claim_id`
(`get_claim` -> insert/update); insert espelha status real do BACEN (`bacen_sync_changeset`, `entry_claim.ex:98-108`);
so publica `monetarie.dict.claims.inbound_received` quando `status=="OPEN" and donor_ispb==own` (`claims.ex:571-573`);
agenda timers de quarentena via `schedule_synced_claim_deadlines` (`claims.ex:577,1703-1745`). NAO ha auto-cancel
antifraude de portabilidade com documento divergente (ver g3).

---

## 9. GAPS

### g1 — Prazos de OUTBOUND hardcoded (14/30d) ignoram os periodos do BACEN — DIVERGENCIA (risco medio)
- LEGADO: persiste `ResolutionPeriodEnd`/`CompletionPeriodEnd` da resposta do BACEN (`Infrastructure:6038-6039`);
  worker so detecta vencimento por esses campos (`Infrastructure:8735,8785,8831`).
- NOSSO: `create_claim` grava `donor_deadline=now+14d`, `claimer_deadline=now+30d` (`claims.ex:105-106,1628-1630`);
  `create_claim_via_bacen` extrai da resposta SO o `claim_id` (`claims.ex:990-993`) e ignora
  `resolution_period_end`/`completion_period_end`, que o parser ja devolve (`response_parser.ex:60-61,235-236`).
  Timers do outbound ficam ancorados no relogio local (14/30d) em vez da janela real do BACEN.
- Impacto: auto-resolucao pode disparar em instante diferente do prazo BACEN; janela do doador local = 14d vs
  resolucao BACEN tipica de 7d. O sync inbound (`claims.ex:688-692`) usa os periodos do BACEN — a divergencia e so no OUTBOUND.

### g2 — OUTBOUND agenda timer de DOADOR sem checar papel; pode auto-confirmar claim onde somos REIVINDICADOR — DIVERGENCIA (risco medio)
- LEGADO: auto-confirm do fim de resolucao roda SO para doador (`ListOperacaoResolucaoExpirada(doacao:true, ...)`,
  `App:1440`); `ConfirmaReivindicacao` exige `GetByIdReinvidicacao(..., doacao:true)` (`Infrastructure:4340`).
- NOSSO: em `create_claim` (nos SEMPRE reivindicador — `check_claimer_not_donor`, `claims.ex:1553`),
  `schedule_deadline_events` agenda `CLAIM_DONOR_TIMEOUT` incondicionalmente (`claims.ex:1676-1681`). No vencimento,
  `auto_resolve_on_donor_timeout` -> `auto_confirm_on_donor_timeout` faz `Repo.update` local para CONFIRMED + publica
  `monetarie.dict.claims.auto_confirmed` SEM checar papel e SEM chamar o BACEN (`claims.ex:892-927`).
- Impacto: estado local CONFIRMED espurio e evento auto_confirmed para consumidores numa claim de saida onde o doador
  e outra IF. O `schedule_synced_claim_deadlines` do INBOUND ja gata por papel (`claims.ex:1709-1727`); o OUTBOUND nao.
  Mitigacao parcial: o proximo poll `claims_claimer` sobrescreve com a verdade do BACEN.

### g3 — Sem auto-cancel antifraude de portabilidade inbound com documento divergente — AUSENTE (risco medio)
- LEGADO: `CarregarNaoIntegradas` (`Infrastructure:6791-6804`): doador que recebe claim OPEN/WAITING e (sem chave local
  OU portabilidade com documento != titular local) cancela AUTOMATICAMENTE (FRAUD/DEFAULT_OPERATION).
- NOSSO: `materialize_inbound_claim` so espelha e emite `inbound_received` (`claims.ex:548-573`); nenhuma logica de
  auto-cancel por divergencia de documento na entrada.
- Impacto: perda de um controle antifraude/coordenacao do legado; portabilidade indevida so seria barrada por acao
  manual do doador ou pelo desfecho do BACEN.

### g4 — Sem validacao local de EVP e de OWNERSHIP em chave CPF/CNPJ — AUSENTE (risco medio)
- LEGADO: `ValidaTipoEVP` (`App:1138-1144`) bloqueia reivindicar EVP; `ValidaPermissao` (`App:1130-1136`) bloqueia
  OWNERSHIP para CPF/CNPJ. Fail-fast ANTES de assinar/enviar ao BACEN.
- NOSSO: `create_claim` nao bloqueia nenhum dos dois (`claims.ex:80-114`); `determine_claim_type` deriva o tipo por
  documento sem vetar EVP nem OWNERSHIP-em-CPF (`claims.ex:1614-1620`). Em `:bacen` o BACEN rejeita, mas em
  local/simulador a claim invalida e aceita, e a UX perde o erro claro pre-envio.

### g5 — Sem matriz de motivo (tpMotivo) em confirm/cancel — PARCIAL (risco baixo)
- LEGADO: `ConfirmaReivindicacao` so aceita motivo por tipo (OWNERSHIP: USER_REQUESTED/DEFAULT_OPERATION;
  PORTABILITY: USER_REQUESTED/ACCOUNT_CLOSURE — `Infrastructure:4353`); `CancelaReivindicacao` valida matriz complexa
  por tipo/papel/situacao/FRAUD (`Infrastructure:4536`).
- NOSSO: `confirm_claim`/`cancel_claim` so validam papel e estado; `cancel_claim` aceita qualquer `reason` livre
  (`claims.ex:275-315`), sem casar motivo x tipo x papel. Motivos validos existem so como lista (`claims.ex:37`).

### g6 — Sem gate de janela de horario nas operacoes de claim — AUSENTE (risco baixo)
- LEGADO: `ValidaHorario(Reivindicar|Doar)` em abrir/confirmar/cancelar/concluir (`Infrastructure:5931,4329,4507,4693,4825`).
- NOSSO: nenhuma verificacao de janela de horario do participante nas operacoes de claim (`claims.ex`).

---

## 10. Itens COBERTOS (confianca)

- c1 — Maquina de 5 estados OPEN/WAITING_RESOLUTION/CONFIRMED/CANCELLED/COMPLETED com transicoes validadas.
  Legado `TB_TIPOSITUACAO` (vivo) + `Infrastructure:6033,4368,4556,4778`; nosso `entry_claim.ex:14,151-161`.
- c2 — Derivacao PORTABILITY (mesmo documento) vs OWNERSHIP (documento diferente).
  Legado deriva por doador/reivindicador; nosso `determine_claim_type` (`claims.ex:1614-1620`).
- c3 — Auto-resolucao no fim da resolucao (doador): OWNERSHIP confirma, PORTABILITY cancela.
  Legado `App:1397` (confirm) / `App:1330` (cancel); nosso `claims.ex:778-828`.
- c4 — Auto-resolucao no fim da conclusao (reivindicador): OWNERSHIP CONFIRMED conclui, senao cancela, com fallback.
  Legado `App:1945-1993` + `App:1817-1848`; nosso `claims.ex:841-886,933-971`.
- c5 — Equalizacao inbound nos DOIS papeis (doador+reivindicador), incremental por watermark, idempotente por claim_id.
  Legado fases 1-3 (`App:1600,1627,1658,5985,6238`); nosso `inbound_sync.ex:74,244-248` + `claims.ex:495-619`.
- c6 — Ciclo de vida acknowledge/confirm/cancel/complete com gating de papel (doador confirma/acknowledge; reivindicador
  conclui; ambos cancelam). Legado claimsController + UnitOfWork; nosso `claims.ex:141-315,437-447` (`check_requester_is_*`).
- c7 — Bloqueio de claimer==doador / portabilidade para a mesma IF.
  Legado `Infrastructure:5937-5944`; nosso `check_claimer_not_donor` (`claims.ex:1553-1554`).
- c8 — Validacao de posse antes de concluir (conceito dos estados locais 101/102 WAITING_VALIDATION/KEY_INCLUDED),
  reimplementada por OTP scope CLAIM para PHONE/EMAIL sob flag `DICT_OWNERSHIP_ENFORCED`.
  Nosso `ownership.ex:118-131` + gate em `complete_claim` (`claims.ex:234`).
- c9 — Materializacao inbound idempotente por claim_id com status real do BACEN + timers de quarentena tambem no sync.
  Legado `Infrastructure:6755-6818`; nosso `claims.ex:548-608,1703-1745`.
- c10 — Transferencia da chave ao reivindicador na conclusao. Legado `ConcluiReivindicacaoBase` (`Infrastructure:4746-4810`,
  reatribui Contadict + recalcula CID); nosso `transfer_key_to_claimer` em `complete_claim` (`claims.ex:1245-1269,1640-1656`).

Nota (info) — na conclusao o legado recalcula o `IdCID` da chave (`Infrastructure:4759`); nosso `complete` transfere a
entry sem recomputar CID no fluxo de claim (o CID/sync da entry vive no dominio de chaves/CID, fora deste modulo). Sem
prova de defeito; registrado como informativo.
