# Mapeamento contratual da observabilidade do Contas

O Contas usa o mecanismo genérico `ObservabilityCodeMapper` do framework para adaptar **identificadores internos de observabilidade** aos códigos exigidos pelo contrato externo.

Arquivo:

```text
config/observability_mapping.yaml
```

Configuração de exemplo deste agente:

```yaml
version: "1"
mappings:
  guardrail.dlex_in: GRL.004
  guardrail.tox: GRL.005
```

O mapping é feito pelo nome canônico emitido internamente. Assim, uma generation/observation criada como `guardrail.dlex_in` aparece externamente como `GRL.004`, e `guardrail.tox` como `GRL.005`.

A substituição acontece antes dos providers de observabilidade. O mesmo nome contratual é usado por Langfuse, OTEL e EventBus nos caminhos que passam por `Telemetry`. Eventos publicados pelo `AgentObserver` também continuam usando o mesmo mapper.

Quando um nome de span/generation é substituído, o nome interno é preservado em metadata:

- `observability_name_internal`
- `observability_name_mapped`
- `observability_code_mapped: true`

Para eventos estruturados, permanecem disponíveis os campos equivalentes `event_code_internal` e `event_code_mapped`.

Códigos/names ausentes na tabela passam sem alteração. Para acrescentar outro contrato, adicione somente uma nova entrada ao YAML; não altere Python nem o guardrail/judge.

Este arquivo pertence ao agente/deployment. O framework contém apenas a engine genérica de mapping e não conhece os códigos contratuais deste agente ou de qualquer cliente.

## Diagnóstico de carregamento

No startup o agente registra uma linha `Observability mapping:` com `enabled`, `path`, quantidade de entradas, amostras resolvidas e o arquivo real de onde `agent_framework` foi importado. Isso permite detectar `.venv` antigo/cópia errada do framework e path relativo incorreto.

A normalização é aplicada em duas barreiras:

1. `Telemetry._start_observation()` — última barreira para spans/generations criados pelo Telemetry;
2. `LangfuseAnalyticsPublisher` — necessário porque esse publisher usa o SDK Langfuse diretamente e não passa pelo Telemetry.

Assim, uma configuração como:

```yaml
mappings:
  guardrail.dlex_in: GRL.004
  guardrail.tox: GRL.005
```

é aplicada independentemente de qual dos dois caminhos produziu a observation.

## Normalização na fronteira do LLM provider

A normalização não depende apenas do `Telemetry`. O `generation_name` é resolvido pelo `ObservabilityCodeMapper` antes de o provider LLM iniciar qualquer instrumentação. Isso garante que nomes como `guardrail.dlex_in` já cheguem ao tracer como `GRL.004`.

Quando o provider já recebe o `Telemetry` do framework, a auto-instrumentação `langfuse.openai` é desabilitada para evitar uma segunda observation fora do contrato central.

O caminho relativo configurado em `OBSERVABILITY_CODE_MAPPING_PATH` é procurado no diretório corrente e nos roots de importação Python, permitindo iniciar o Uvicorn fora do diretório raiz do agente sem perder o mapping.

## Compatibilidade automática do framework

A partir desta versão, o framework possui um registry default interno (`agent_framework/config/observability_mapping.yaml`) carregado mesmo quando o agente não possui `OBSERVABILITY_CODE_MAPPING_*`. O arquivo do agente, quando habilitado, funciona como overlay. Isso permite substituir somente a versão do framework em agentes legados sem mudar a taxonomia GRL nem as decisões históricas dos rails.

Veja também `agent_framework_oci/libs/agent_framework/docs/OBSERVABILITY_DEFAULT_OVERLAY_COMPATIBILITY.md`.
