# Changelog de divergência: BCP vs UCP

Registro consciente do fork. Atualizado a cada sync com o upstream.

## Baseline

- **BCP deriva do UCP `2026-04-08`** (spec vendorada em `schemas/` e `discovery/`).
- `discovery/profile_schema.json` (documento de well-known) vendorado inicialmente
  com `$id` `ucp.dev` → `bcp.dev.br`. Diferente do `ucp_sdk`, geramos o pydantic dele
  (`bcp_sdk.models.discovery.profile_schema`), porque o índice valida profiles em runtime.
- `services/` (OpenAPI/OpenRPC) ainda **não** vendorados (ver README); `handlers/`
  agora traz o primeiro handler original do BCP (`pix`), não um vendorado do UCP.

## O que seguimos do UCP

- JSON Schema draft 2020-12, reverse-domain naming, `extends`/`allOf`.
- Versionamento por data, open enums, `ucp_request` (omit/optional/required por op).
- Authority binding, serialização canônica (JCS) para assinatura.
- Anotação `ucp_request` mantida com o mesmo nome (convenção do validador, não namespace).

## O que renomeamos

- `dev.ucp.*` → `br.dev.bcp.*` (nomes de capability, `extends`, chaves de `$defs`).
- `https://ucp.dev/...` → `https://bcp.dev.br/...` (em `$id` e URLs).
- `/.well-known/ucp` → `/.well-known/bcp` para descoberta do perfil comercial.
- `a2a.ucp.*` → `a2a.bcp.*` nas chaves estruturadas da extensão A2A.
- Mantidos como estão: nomes de arquivo (`ucp.json`), o campo de envelope `ucp`, e a
  palavra-chave `ucp_request` (renomear quebraria o validador sem ganho).

## O que divergimos de propósito

- O binding A2A acompanha a versão estável 1.0: Agent Card com
  `supportedInterfaces`, extensões em `capabilities.extensions`, header
  `A2A-Extensions` e Parts discriminados pelo nome do membro. O caminho padronizado
  do Agent Card permanece `/.well-known/agent-card.json`; interfaces BCP usam
  `/bcp/a2a` nos exemplos.
- Perfis BCP publicam o JWK Set canônico em `keys[]`. O schema local acompanha o
  texto normativo do BCP, em vez do campo `signing_keys` do baseline UCP.

Extensões brasileiras (originais do BCP, sem linhagem UCP — Copyright 2026 BCP
Authors), todas por `allOf` sobre os recursos base, sem editar nenhum schema
vendorado. Requisitos e base legal em `docs/specification/*.md` e no documento
de requisitos das issues #6/#7/#8:

- `br.dev.bcp.shopping.fiscal_identity` (`schemas/shopping/fiscal_identity.json`):
  CPF/CNPJ do comprador no `buyer` + identidade do vendedor (CNPJ, razão social,
  endereço) obrigatória em toda resposta de checkout/order (CDC art. 31;
  Decreto 7.962/2013). Estende checkout e order.
- `br.dev.bcp.shopping.tax` (`schemas/shopping/tax.json`, NCM em `types/ncm.json`):
  detalhamento tributário por line item (tipo aberto: icms/iss/difal/ibs/cbs/is,
  alíquota, base, valor, nível federativo, comportamento no preço) + NCM
  (Lei 12.741/2012). O `authority` expõe o nível federativo ao consumidor e serve
  de base ao split payment 2027+. Sem config de perfil: regime é atributo de
  AgentFacts e o cálculo roda atrás do port da RFB. Estende checkout e order.
  A obrigatoriedade da linha `tax` em `totals` é regra normativa da spec, não
  constraint de schema (`contains` quebra a geração de modelos, testado); quem a
  faz valer é o binding (`bcp_infra/tax/bcp_mapping.py`), com fail fast.
  Revisão `2026-07-14`, ao trazer o tributo para código (issue #26):
  - `behavior` (`inclusive`/`exclusive`), **obrigatório** em toda incidência: sem
    ele `subtotal + Σtaxes` não reconcilia com `total`, porque entre 2026 e 2032 o
    mesmo item carrega ICMS por dentro do preço e IBS/CBS calculados por fora.
    É o único campo do cálculo que o comprador precisa ver — o resto (CST,
    cClassTrib, CFOP, CEST, origem, regime, código IBGE) é insumo de cálculo e
    fica no domínio, como o `FiscalClassification` da `nfe` já fez.
  - `subnational` sai do vocabulário de `authority`: as esferas da Lei 12.741 são
    três, e o IBS partilhado vira duas entradas (`state` + `municipal`), que é como
    a calculadora da RFB devolve (`gIBSUF`/`gIBSMun`) e como a NF-e destaca.
  - `pattern` de 8 dígitos do NCM restaurado (regressão de `fa4b99b`, que extraiu o
    tipo para `types/ncm.json` e perdeu a constraint pelo caminho).
  - `settlement` (recolhido/dispensado/retido) foi **considerado e descartado**: em
    2026 o IBS/CBS destacado é dispensado de recolhimento e compensável com
    PIS/Cofins, então não muda o preço; se o vendedor recolhe ou não é assunto do
    vendedor, não do comprador — não passa na régua do fio.
- `br.dev.bcp.shopping.nfe` (`schemas/shopping/nfe.json`): referência da NF-e no
  pedido (chave de acesso, DANFE/XML, data de emissão; modelo e protocolo já
  embutidos na chave). Só a referência, minimização LGPD. Opcional (dispensa do
  MEI, LC 123/2006 art. 26). Estende order.
- `br.dev.bcp.shopping.returns` (`schemas/shopping/returns.json` +
  `types/returns_config.json`): arrependimento art. 49 CDC e logística reversa —
  motivo, confirmação imediata do recebimento da manifestação, código de
  postagem reversa; política declarável no `config` do profile. Estende order.
  Revisão `2026-07-27`, ao ligar devolução a reembolso (issue do refund):
  - `refund_adjustment`: o ajuste de `refund` passa a exigir totais negativos.
    O UCP já modela reembolso como ajuste financeiro (tipo, status, valor,
    momento), mas não restringe o sinal: hoje um total de `refund` positivo
    valida. É o único aperto que o reembolso pedia.
  - `related_adjustment_ids` em `order_adjustment`: como `status` é um valor só,
    devolução e reembolso precisam ser dois ajustes, e dois ajustes precisam de
    vínculo. Fica no estreitamento da extensão, não no `adjustment` vendorado.
  - `if`/`then` no lugar de `oneOf`/`not` para aplicar os campos de devolução
    apenas quando `type` é `return`, seguindo `total.json`, `totals.json` e
    `pagination.json` do baseline. O `oneOf` exigia um tipo de escape
    (`non_return_adjustment`) que não significava nada no domínio e cuja
    exclusividade o gerador de modelos descartava.
  - **Considerado e descartado**: `payment_reference` no ajuste, `PixRefundDetails`
    no handler Pix e `payment_handlers` na resposta de order. Os três levariam ao
    fio a mecânica de execução do pagamento (ids de PSP, liquidação, trilho usado),
    que o UCP mantém deliberadamente entre vendedor e PSP, por webhook do provedor
    (`overview.md`, "Settlement confirmation reaches the business through the payee
    PSP's webhook"). Quem estorna é o vendedor, que já tem esses ids; não há
    consumidor cross-party, e publicá-los vazaria identificador de PSP. A regra
    virou texto normativo em `docs/specification/returns.md`.
- `br.dev.bcp.pix` (`schemas/handlers/pix/pix.json`): payment handler de Pix
  Cobrança única (QR dinâmico, fluxo push), original do BCP. `allOf` sobre
  `payment_handler.json` e sobre os tipos base de instrumento/credencial
  (`payment_instrument`, `payment_credential`, `binding`). Escopo: cobrança
  única; Pix Automático/ITP fica para handler irmão futuro. Divergência de
  layout: o handler concreto vive em `schemas/handlers/` (não numa árvore
  `source/handlers/` separada como o UCP), porque o bcp-index é autoridade e
  implementação de referência e o handler alimenta a geração de modelos.

Validação (substitui o plano original de `validate_examples.py`, que **não existe
no upstream** — premissa corrigida): CLI oficial `ucp-schema` (crates.io).
Confirmado empiricamente na v1.3.0: o authority binding é genérico e aceita
`br.dev.bcp.*` ↔ `bcp.dev.br` sem fork nem config; `lint` valida os `examples`
embutidos (regra E008); fixtures de ponta a ponta em `fixtures/{valid,invalid}/`
rodam via `scripts/validate.sh`.

## O que decidimos NÃO puxar do upstream

- (nada ainda; registrar por release UCP futura, com a razão.)
