Agent Mentor Learn
Observabilidade e depuração: enxergando cada passo do seu agente · Lição 4 de 6

Lição 4: Tracing: costurando uma execução em uma árvore

Objetivos de aprendizado:

  • Usar IDs de correlação para juntar registros espalhados em “tudo o que um prompt disparou”, e explicar como isso divide o trabalho com os IDs de sessão
  • Ler a hierarquia de spans e traces: span raiz, requisições de modelo, chamadas de ferramenta, as duas fases de uma ferramenta (espera de permissão e execução) e como subagentes se aninham sob o span de ferramenta do agente pai
  • Quando o painel está vazio, desconfiar do pipeline antes de desconfiar do agente: saber por que a exportação falha em silêncio, em que condições a exportação em lote perde dados e como verificar a própria instrumentação

Pré-requisitos: Lições 1–3 (por que o não determinismo quebra a reprodução, por que os registros brutos são a evidência de primeira mão, como instrumentar um harness com logs estruturados e métricas) | << Lição 3 | Lição 5 >>

400 registros — quais 12 são daquela execução?

No fim da lição anterior, seu harness estava gravando registros estruturados em runs.jsonl: um por requisição de modelo, um por chamada de ferramenta, com duração, tokens e erros. Os logs saíram de “um blocão de texto” para “um objeto JSON por linha”. Você estava satisfeito.

Aí um usuário relata um problema: “Ontem à tarde eu pedi para arrumar um texto na página de login e ele também mexeu num arquivo de teste. Eu não pedi isso.”

Você abre os logs, filtra por data com grep e 400 registros encaram você de volta. Duzentas chamadas de ferramenta, cem requisições de modelo e dezenas de registros de subagentes misturados no meio. O prompt de que o usuário está falando provavelmente corresponde a uns doze deles. Quais doze?

Você tem duas pistas, nenhuma suficiente:

  • ID de sessão. Na lição anterior você chegou a gravar session_id em cada registro, mas ontem à tarde o usuário teve umas sete ou oito idas e vindas na mesma sessão. Filtrando por sessão, 400 vira 210. Faixa menor, mesma natureza.
  • Marca de tempo. Você pode chutar uma janela de tempo e cortar por ali, mas os subagentes rodaram simultaneamente e os registros deles se intercalam com os do loop principal na linha do tempo; e a “tarde” do usuário tanto pode ser 14h quanto 16h, ele não lembra.

O problema não é falta de detalhe nos registros — é que os registros não têm relações. A lição 3 transformou cada etapa em dado, mas esse dado é uma pilha de linhas paralelas. Qual linha causou qual, quem é filho de quem — nem uma palavra sobre isso. Centenas de objetos JSON bem formatados, ainda assim uma pilha de areia — só que desta vez uma areia mais quadradinha.

Esta lição acrescenta essa camada que falta.

ID de correlação: o crachá de um prompt

A etapa mais simples: dê um ID a “um evento disparador” e faça todo evento gerado por esse disparador copiar esse ID. Isso é um ID de correlação. Não precisa de infraestrutura nenhuma — é só um campo.

O desenho nativo do Claude Code faz exatamente isso. Depois que um usuário envia um prompt, o Claude Code pode fazer várias chamadas de API e rodar várias ferramentas; o atributo prompt.id permite amarrar todos esses eventos de volta ao único prompt que os disparou1. A receita de depuração que a documentação dá é igualmente direta: para rastrear toda a atividade disparada por um único prompt, filtre seus eventos por um valor específico de prompt.id1.

Este ID e o ID de sessão são duas granularidades diferentes, cada uma com sua função:

ID de correlaçãoAbrangênciaResponde a que pergunta
id de sessãoUma conversa inteiraQuanto esta sessão custou no total? Ela mudou de modo de permissão?
id de promptUm prompt dentro de uma sessãoQuais requisições de modelo e chamadas de ferramenta a frase de que o usuário está reclamando disparou de fato?

De volta aos 400 registros da abertura: se cada registro carregasse prompt_id, bastava achar na transcrição da sessão o id correspondente a “arrumar um texto na página de login”, filtrar uma vez, e 400 cai para 12. Pela primeira vez a areia tem uma borda.

Mas borda não é estrutura. Aqueles 12 registros continuam sendo 12 linhas planas. Você ainda não sabe se a edição errada no arquivo de teste veio direto do loop principal ou de um subagente que ele despachou; não sabe se aquela ferramenta de 40 segundos passou 40 segundos esperando você clicar em “aprovar”.

Spans e traces: arrumar eventos em uma árvore

Deixe eu traduzir alguns termos primeiro, já que vamos usá-los daqui para a frente:

  • span: O registro de “um pedaço de trabalho com começo e fim”. Tem um nome (como llm_request), um horário de início, um horário de fim e alguns atributos pendurados nele (nome do modelo, nome da ferramenta, contagem de tokens). Um span consegue identificar o span pai dele.
  • trace: Uma árvore inteira de spans conectados por relações pai-filho. Tudo o que aconteceu durante uma requisição completa, do começo ao fim, lido como uma árvore.
  • exportador (exporter): O código dentro do processo responsável por empacotar spans e mandá-los para fora.
  • coletor (collector): A estação de retransmissão ou serviço de backend que recebe esses spans. O exportador manda os dados para ele; você vê a árvore no painel dele.

O tracing distribuído do Claude Code exporta spans que ligam cada prompt do usuário às requisições de API e execuções de ferramenta que ele dispara, de modo que você consegue ver uma requisição completa como um único trace no seu backend de tracing1. A hierarquia específica é esta: cada prompt do usuário inicia um span raiz claude_code.interaction; chamadas de API, chamadas de ferramenta e execuções de hook são gravadas como filhos dele; os spans de ferramenta têm dois spans filhos próprios — um para o tempo passado esperando por uma decisão de permissão e outro para a execução em si1.

Vale parar nesses dois spans filhos de uma ferramenta. Na lição anterior você gravou duration_ms: uma ferramenta rodou por 40 segundos. Mas “40 segundos dos quais 38 foram esperando alguém clicar em aprovar” e “40 segundos dos quais 38 foram rodando o comando” são dois problemas completamente diferentes. O primeiro significa arrumar a configuração de permissões ou mudar o padrão de interação; o segundo significa arrumar a implementação da ferramenta. Os mesmos 40 segundos, partidos em dois trechos, dão duas correções diferentes. É isso que a estrutura em árvore dá além dos campos planos.

O Agent SDK diz de forma ainda mais direta: traces são a visão mais detalhada que você consegue de uma execução de agente; com CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1 definido, cada etapa do loop do agente vira um span que você pode inspecionar no seu backend de tracing2. A CLI já traz instrumentação OpenTelemetry embutida: ela grava spans em torno de cada requisição de modelo e execução de ferramenta, emite métricas para contadores de token e custo e emite eventos de log estruturados para prompts e resultados de ferramenta2.

Compare isso com o harness que você escreveu no curso 7 desta série (“Fundamentos do Harness de Agente: Laços e Controle”): seu loop já tem posições claras — “enviar requisição / receber tool_use / rodar ferramenta / devolver tool_result” — e cada posição mapeia naturalmente para um span. Não faltam posições, falta relação pai-filho.

Propagação através de fronteiras: subagentes, sua aplicação, subprocessos Bash

Uma árvore fica bonita, mas uma execução real atravessa várias fronteiras de processo. A árvore consegue continuar conectada depois da travessia? Consegue, passando “quem é meu pai” para baixo o caminho todo.

Uma camada para baixo: subagentes. Quando o agente gera um subagente pela ferramenta Agent, os spans llm_request e tool do subagente se aninham sob o span claude_code.tool do agente pai, de modo que a cadeia de delegação completa aparece como um único trace2. Isso resolve uma pergunta que fica sem resposta sem a árvore — de quem são os tokens do subagente? Eles estão aninhados sob aquela chamada de ferramenta, que está aninhada sob aquele prompt, então pertencem àquele prompt. Você não precisa de costura extra.

Uma camada para cima: sua aplicação. O SDK propaga automaticamente o contexto de trace W3C para dentro do subprocesso da CLI. O contexto de trace W3C é só uma string padronizada contendo o id do trace e o id do span atual — quem a recebe sabe onde se pendurar. Quando você chama query() enquanto um span do OpenTelemetry está ativo na sua aplicação, o SDK injeta TRACEPARENT e TRACESTATE no ambiente do processo filho, a CLI os lê e o span claude_code.interaction dela vira filho do seu span — a execução do agente aparece dentro do trace da sua aplicação em vez de virar uma raiz desconectada2.

Essa diferença é bem prática na hora de investigar produção: o usuário reclama “cliquei naquele botão e a página ficou girando por 20 segundos”. Você entra no trace da requisição HTTP e consegue seguir até a chamada de ferramenta dentro do agente que levou 14 segundos, sem trocar de sistema nem alinhar marcas de tempo.

Mais para baixo ainda: os comandos que o próprio agente roda. Quando o tracing está ativo, subprocessos Bash e PowerShell herdam automaticamente uma variável de ambiente TRACEPARENT contendo o contexto de trace W3C do span da execução de ferramenta ativa1. Se um comando lançado pela ferramenta Bash emite os próprios spans do OpenTelemetry, esses spans se aninham sob o span claude_code.tool.execution que envolve o comando2.

Ligue os três trechos e uma árvore consegue partir da sua requisição web, passar pela CLI, passar por um subagente e crescer até um estágio de compilação dentro do npm run build que o agente rodou.

Só estrutura, nada de conteúdo

Você deve estar se perguntando: se cada etapa que o agente dá é enviado para um backend externo, isso inclui o que o usuário disse a ele e o conteúdo dos arquivos que ele leu e escreveu?

O post-mortem da Anthropic sobre o sistema multiagente de pesquisa dá duas conclusões paralelas. Uma é o ganho: depois que colocaram o tracing completo no ar, eles conseguiram diagnosticar por que os agentes falhavam e corrigir os problemas sistematicamente3. A outra é o limite: eles monitoraram padrões de decisão e estruturas de interação dos agentes sem monitorar o conteúdo das conversas individuais, para preservar a privacidade dos usuários; mesmo essa observabilidade de alto nível ajudou a diagnosticar causas-raiz, descobrir comportamentos inesperados e corrigir falhas comuns3.

A postura padrão das ferramentas nativas se alinha exatamente a esse princípio. A telemetria é estrutural por padrão: durações, nomes de modelo e nomes de ferramenta são gravados em cada span; contagens de token são gravadas quando a requisição de API subjacente devolve dados de uso, então spans de requisições que falharam ou foram abortadas podem omiti-las; o conteúdo que seu agente lê e escreve não é gravado por padrão2. O conteúdo dos prompts do usuário também não é coletado por padrão — só o comprimento do prompt é gravado; para incluir o conteúdo do prompt, você precisa definir explicitamente OTEL_LOG_USER_PROMPTS=11. A página do Agent SDK coloca o mesmo lembrete ao lado das próprias chaves de coleta de conteúdo: deixe essas chaves desligadas a menos que seu pipeline de observabilidade esteja aprovado para armazenar os dados que seu agente manipula2.

Para muitos times isso é uma boa notícia: você não precisa ganhar uma batalha de conformidade sobre “podemos mandar conteúdo do usuário para um backend de terceiros” antes de começar a enxergar o que seu agente faz. Muitos problemas são visíveis na camada de estrutura.

Ao projetar traces para o seu próprio harness, trate isso como o padrão: grave nos spans nomes, durações, nomes de ferramenta, contagens de token e tipos de erro; deixe o conteúdo de parâmetros e retornos nos registros brutos locais (da lição 2) e busque-os por id quando precisar.

O próprio pipeline de observabilidade pode mentir para você

Tudo até aqui foi sobre “o que você consegue ver depois que a árvore está montada”. Esta seção é sobre algo que acontece antes e é mais fácil de queimar você: você acha que está olhando para dados, mas na verdade está olhando para um painel vazio.

A primeira coisa a lembrar: falha de exportação é silenciosa por padrão. Se o endpoint está inacessível ou o backend rejeita os dados, o agente continua rodando normalmente e a CLI descarta a telemetria sem levantar erro nenhum na sua aplicação2. Esse desenho está correto — o pipeline de observabilidade não deveria derrubar o fluxo principal — mas o custo é que um pipeline quebrado e tudo funcionando ficam idênticos do seu lado.

A segunda coisa: a exportação em lote perde dados sob condições específicas. A CLI agrupa a telemetria em lotes e exporta em intervalos. Numa saída limpa do processo ela tenta descarregar os dados pendentes, mas esse descarregamento é limitado por um timeout curto, então spans ainda podem ser perdidos se o coletor demorar a responder; se o seu processo for morto antes de a CLI desligar, tudo o que ainda estiver no buffer do lote é perdido2. Por padrão, métricas são exportadas a cada 60 segundos e traces e logs a cada 5 segundos2. Junte essas frases: uma execução curta de agente em CI que termina em três a cinco segundos depende de “o descarregamento completar dentro do timeout E o processo não ser morto antes” para preservar a telemetria da ponta final — e o intervalo de exportação amplia a quantidade parada no buffer. Cenários assim precisam de intervalos de exportação bem mais curtos que a duração da execução, e você precisa garantir que o processo saia de forma limpa.

A terceira coisa, e o que você deve fazer primeiro ao investigar: verifique a própria instrumentação (instrumentação é só outra palavra para as sondas que você instalou). Para verificar uma configuração que exporta métricas, procure no seu backend pela métrica claude_code.session.count — o Claude Code a emite quando uma sessão começa1; se nada chegar, rode claude --debug e procure erros de exportação OTel no log de depuração1. O valor dessas duas etapas é que eles separam “o agente tem um problema” e “o pipeline está funcionando” em duas perguntas que se respondem separadamente.

Mais duas armadilhas de configuração em que é fácil pisar:

  • Por padrão, a CLI reporta service.name como claude-code. Se você roda vários agentes, ou roda o SDK ao lado de outros serviços que exportam para o mesmo coletor, sobrescreva o nome do serviço e adicione atributos de recurso para conseguir filtrar por agente no seu backend2. Do contrário os spans de três agentes se misturam sob o mesmo nome de serviço e você fica olhando para uma sopa.
  • Ao rodar pelo SDK, não defina console como valor de exportador2. A documentação não diz por quê; pelo jeito como o SDK e a CLI se comunicam, o SDK fala com a CLI pela stdout, e imprimir spans ali embaralharia esse canal.

Três sinais, você liga só os que precisa

Você não precisa ligar o pacote completo de uma vez. A CLI exporta três sinais OpenTelemetry independentes — métricas, eventos de log e traces — cada um com sua própria chave de ativação e seu próprio exportador, então você pode ligar só os que precisa2.

Isso dá uma sequência natural de adoção:

  1. Ligue as métricas primeiro. Custo e uso de tokens são as primeiras perguntas que as pessoas fazem, métricas são o mais barato e o intervalo padrão de exportação de 60 segundos serve bem para serviços de longa duração.
  2. Depois ligue os eventos de log. Resultados de ferramenta e decisões de permissão — esses eventos estruturados são a matéria-prima dos padrões de leitura diagnóstica da lição 3.
  3. Ligue os traces quando bater num problema que você não consegue explicar. Eles são o mais caro e o mais detalhado — você precisa deles quando de fato tem que “ver o formato de uma execução”.

O destino da exportação é qualquer backend que aceite o OpenTelemetry Protocol (OTLP); a documentação cita alguns: Honeycomb, Datadog, Grafana, Langfuse ou um coletor auto-hospedado2. Qual escolher está fora do escopo deste curso — vou dizer só o seguinte: o fato de os três sinais serem independentes significa que você pode testar as águas com a menor peça primeiro, sem esperar a infraestrutura completa ficar pronta.

De passagem: o mesmo lote de eventos também é trilha de auditoria

Os eventos estruturados têm mais um uso, sem relação com depuração; só saiba que ele existe.

Com a identidade do usuário final anexada, os eventos tool_decision, tool_result, mcp_server_connection e permission_mode_changed, que são exportados como registros de log nomeados com o prefixo claude_code., viram uma trilha de auditoria por usuário que você pode encaminhar para uma plataforma de Security Information and Event Management (SIEM)2. Cada evento carrega atributos de identidade que amarram chamadas de ferramenta, atividade MCP e decisões de permissão de volta ao usuário que as disparou1.

O mesmo lote de dados, lido de outro jeito, é a matéria-prima de outro trabalho: ao depurar você fatia horizontalmente por prompt.id, ao auditar você fatia verticalmente por usuário. Temas de segurança não serão expandidos neste curso.

Respostas que este curso não vai dar

Algumas coisas precisam de limites claros para você não ficar procurando receitas prontas em outro lugar:

  • Taxas de amostragem e janelas de retenção: guardar traces em volume total fica caro, e quanto amostrar e por quanto tempo guardar são perguntas reais, mas não há orientação no material primário, então este curso não vai inventar números. Quando o seu volume de dados virar um problema de verdade, isso fica entre você e a conta do seu backend.
  • Limiares de alerta: mesma coisa — nenhum número é dado.
  • Hooks: como instalar sondas nos pontos de controle do ciclo de vida, o que PreToolUse e PostToolUse conseguem acessar cada um — isso é a lição 5. Uma interface para fincar aqui antes: a entrada do hook carrega o UUID do prompt de usuário sendo processado no momento, e é o mesmo valor do atributo prompt.id nos eventos de telemetria, de modo que a saída do hook e a telemetria do mesmo prompt podem ser correlacionadas4. O ID de correlação estabelecido nesta lição fica diretamente utilizável na próxima.
  • Seu próprio harness não precisa de OTel completo. Esta lição usa o desenho nativo como ferramenta de ensino porque ele expõe toda a estrutura que deveria existir. Mas o que você quer de fato é só a árvore: a lição 6 vai gerar um trace_id para cada execução, adicionar span_id e um campo de ponteiro para o pai em cada registro e então escrever uma dúzia de linhas de código para imprimir isso indentado — você vai obter uma árvore construída com o mesmo mecanismo pai-filho (a lição 6 vai explicar que ela escolheu um pai diferente para as ferramentas), sem coletor, sem backend, sem dependências. Se um dia você precisar mesmo conectar OTLP, os campos já estarão lá.

💻 Exercícios

Recapitulação

  • Logs estruturados resolveram “os registros são detalhados o bastante”, mas não resolveram “que relação os registros têm”. IDs de correlação são a primeira etapa para adicionar relações: um prompt pode disparar várias chamadas de API e várias ferramentas, e prompt.id amarra todos esses eventos de volta ao único prompt que os disparou; a jogada inicial de depuração é filtrar por esse valor1.
  • Um span é o registro de um pedaço de trabalho com começo e fim; um trace é a árvore costurada pelas relações pai-filho. O tracing distribuído liga cada prompt do usuário às requisições de API e execuções de ferramenta que ele dispara como spans, de modo que a requisição completa se lê como um único trace no seu backend de tracing1.
  • A hierarquia é fixa: cada prompt abre um span raiz claude_code.interaction, e chamadas de API, chamadas de ferramenta e execuções de hook são filhos dele; os spans de ferramenta têm dois spans filhos que gravam separadamente o tempo de espera por permissão e o tempo de execução propriamente dita1. Com a telemetria aprimorada ligada, cada etapa do loop do agente vira um span inspecionável; traces são a visão mais detalhada de uma execução2.
  • Árvores conseguem continuar conectadas através de fronteiras de processo: os spans do subagente se aninham sob o span de ferramenta do agente pai, e a cadeia de delegação completa se lê como um único trace; o SDK injeta TRACEPARENT e TRACESTATE no subprocesso da CLI, então a execução do agente aparece dentro do trace da sua aplicação em vez de virar uma raiz desconectada2; descendo mais, subprocessos Bash herdam TRACEPARENT1, e os spans emitidos por comandos se aninham sob o span daquela execução de ferramenta2.
  • Colocar o tracing completo no ar habilita o diagnóstico sistemático de falhas3; e monitorar apenas padrões de decisão e estruturas de interação, sem olhar o conteúdo das conversas, é suficiente para diagnosticar causas-raiz e descobrir comportamentos inesperados3. O mecanismo se alinha exatamente: a telemetria é estrutural por padrão — durações, nomes de modelo e nomes de ferramenta são gravados em cada span; conteúdo não é gravado por padrão2; o conteúdo dos prompts também é, por padrão, só comprimento; para incluir conteúdo é preciso definir uma chave explicitamente1.
  • Métricas, eventos de log e traces são três sinais independentes, cada um com sua própria chave de ativação e seu próprio exportador, então você pode ligar só os que precisa2 — adoção incremental, sem precisar apostar tudo de uma vez.
  • O próprio pipeline de observabilidade pode mentir para você: falha de exportação é silenciosa por padrão, o agente roda normalmente enquanto a telemetria é descartada e nenhum erro é levantado2; a exportação em lote tenta descarregar numa saída limpa, mas é limitada por um timeout curto, e se o processo for morto o buffer é perdido por inteiro2; por padrão métricas a cada 60 segundos, traces e logs a cada 5 segundos2, então execuções curtas precisam de intervalos menores. A primeira coisa ao investigar é verificar a própria instrumentação: procure no backend aquela métrica de contagem de sessão1 e, se não estiver lá, ligue --debug para ver os erros de exportação1.
  • Duas armadilhas de configuração: vários agentes compartilhando um backend precisam sobrescrever service.name e adicionar atributos de recurso para ficarem distinguíveis2; ao rodar pelo SDK, não defina console como exportador2.
  • O mesmo lote de eventos estruturados, lido de outro jeito, é material de auditoria: com atributos de identidade anexados, decisões de ferramenta, resultados de ferramenta, conexões MCP e mudanças de modo de permissão viram uma trilha de auditoria por usuário que você pode encaminhar para um SIEM2, e os atributos de identidade de cada evento amarram as chamadas de ferramenta de volta a quem as disparou1.
  • Não há orientação primária sobre taxas de amostragem e janelas de retenção, então este curso não dá números. Seu próprio harness também não precisa de OTel completo — a lição 6 usa um trace_id mais campos de ponteiro para o pai mais impressão indentada para obter uma árvore construída com o mesmo mecanismo pai-filho.

>> Lição 5: Sondas nas comportas: hooks e um fluxo de depuração

Footnotes

  1. Monitoring — Claude Code Official Documentation — https://code.claude.com/docs/en/monitoring-usage 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

  2. Observability with OpenTelemetry — Claude Agent SDK Official Documentation — https://code.claude.com/docs/en/agent-sdk/observability 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

  3. How we built our multi-agent research system — Anthropic Engineering — https://www.anthropic.com/engineering/multi-agent-research-system 2 3 4

  4. Hooks reference — Claude Code Official Documentation — https://code.claude.com/docs/en/hooks

Exercícios

01

Abaixo estão 14 registros de span de uma execução de agente, um objeto JSON por linha. Eles estão escritos em ordem de horário de fim (um span só sabe sua duração quando termina), então os filhos aparecem muitas vezes antes dos pais.

Nível 1: Desenhe 14 registros planos como uma árvore

Para o problema ficar curto, dobrei o registro filho de “espera de permissão” de cada ferramenta em um campo wait_ms no registro da ferramenta e mantive só o registro filho de execução; end_ms está em milissegundos relativos ao início desta execução.

Sem escrever código, use papel e caneta ou um editor de texto para completar:

  1. Reconstrua esses 14 registros como uma árvore de trace indentada. Irmãos no mesmo nível devem ser ordenados por horário de início, de cima para baixo (horário de início = end_ms - dur_ms). Cada linha deve mostrar nome e duração; marque o nome da ferramenta nas ferramentas.
  2. Responda: nesta execução, os tokens consumidos pelo subagente contam para qual prompt? Por quê? Calcule o total de tokens desse prompt.
  3. Responda: qual único registro consegue provar que build.compile foi disparado pela segunda chamada de ferramenta? Especifique qual campo e qual parte do valor dele.
Critérios de conclusão · marcado localmente
02

Sem código. Os três cenários abaixo vestem a mesma aparência de “o painel parece errado”, mas por baixo são três mecanismos diferentes. Para cada um, escreva: causa mais provável, em que ordem você verificaria e como lidar depois que a verificação passar. Todo julgamento precisa apontar de volta para um mecanismo específico coberto nesta lição — não atribua tudo a “a configuração estava errada”.

Nível 2: Três painéis vazios, dê um caminho de investigação para cada um
  • Cenário A: Exportação de telemetria ligada, subida para produção, passou uma semana, o painel não tem dado nenhum. Nenhum span, nenhuma métrica, nenhum evento. O agente atendeu usuários normalmente a semana toda; ninguém reclamou.
  • Cenário B: O painel de métricas está completamente normal — as contagens de token estão subindo, as curvas de custo estão se mexendo, as contagens de sessão batem. Mas você abre o backend de tracing, busca pela faixa de tempo de hoje e não há um único trace.
  • Cenário C: Um script curto que roda em CI — toda vez que ele termina, o trace está “sem o rabo”: o span raiz está lá, as primeiras etapas estão lá, os dois ou três últimos spans de ferramenta sumiram. A mesma configuração numa máquina de desenvolvimento local, com execuções longas, mostra tudo certinho.
Critérios de conclusão · marcado localmente