badgeIA

Integrations

OpenTelemetry

Understand Badge's gated OTLP receiver contract and current integration readiness.

View Markdown

Release preparation only. Customer setup is not supported yet. The agent-scoped credential, run-correlation backend, and BPP-gated create/rotate/revoke card have shipped, as has a real multi-node evidence run — published end to end in Screen a local Ollama multi-agent app, which is the one worked path that exists today. Version-pinned framework validation has not, so the readiness table below governs every framework that guide does not cover. This page documents the receiver contract without presenting an unverified quickstart.

Whether a given environment accepts OTLP at all is a server-side setting that an operator can change. Check it rather than assuming — the public, no-credential probe GET /api/v1/provenance/status returns {"enabled":true} or {"enabled":false}.

OpenTelemetry traces can describe the model and tool calls an HTTP agent reports, their parent-child relationships, token counts, latency, and self-reported or estimated cost.

Evidence boundary: a Blueprint is self-reported telemetry — consistent with claims, not proof. Badge cross-checks bounded metadata against its registered run and trace context, but the agent still controls the spans it emits. Estimated cost is not provider billing.

Receiver contract

  • Endpoint: POST https://api.badgeia.com/api/v1/provenance/otlp
  • Authentication header: Authorization: Bearer <agent OTLP credential>
  • Transport: OTLP/HTTP with application/x-protobuf or application/json; OTLP/gRPC is not accepted. On the JSON path you do not need to do anything special about ID encoding — Badge accepts both the hex traceId/spanId the OTel spec mandates (what the JS SDK and other conforming http/json exporters send) and the base64 form protobuf's canonical JSON mapping produces. Both are stored identically.
  • Bounds: 1 MiB per request and 200 stored spans per run.
  • Feature gate: when Blueprint/provenance processing is disabled, the receiver returns 404 and this page is excluded from navigation, llms.txt, and the sitemap.

The owner/editor-only backend routes POST /api/v1/agents/{agent_id}/otlp-token and DELETE /api/v1/agents/{agent_id}/otlp-token create, rotate, and revoke a single-reveal credential. The credential is reusable for that agent until rotated or revoked. The agent-detail card masks and single-reveals the value for eligible editors. Customer publication remains blocked until the exact staging trace and compatibility matrix pass.

Every batch authenticated with an agent credential must assign badge.run_id to each effective span partition. The run must belong to that agent, and every trace ID must match a trace Badge registered before dispatch. Badge sends the run ID in X-Badge-Run-Id and W3C trace context in traceparent to an eligible HTTP agent.

Use the exact trace endpoint above with your SDK's trace-specific OTLP HTTP setting. Send the credential only in the authorization header. Never put the credential, a Badge API key, prompts, completions, tool arguments, or tool results in span attributes, URLs, logs, screenshots, or support tickets.

Framework readiness

Unsupported

The SDK's built-in tracing does not become OTLP when standard exporter variables are set.

What Badge reads
Nothing through the built-in tracing path. A separate adapter would need to emit Badge's supported GenAI attributes.
Evidence still required
A selected, security-reviewed, version-pinned adapter exercised against staging.

Partial and reference-only rows are deliberately not copy-paste examples. They become supported only after exact package versions, content-capture controls, accepted-span results, expected Blueprint nodes, and privacy-safe staging receipts are recorded.

Attribute mapping

Badge applies a strict allowlist before persistence. Unknown attributes are discarded.

Exported metadata, Badge interpretation, Notes table
Exported metadataBadge interpretationNotes
Span trace_id, span_id, parent_span_idSequence and invocation edgesStandard OTLP fields, not attributes
Span start/end timestampsPer-node latencyAn end before start is clamped to start and contributes 0ms
gen_ai.response.modelModel nodePreferred over request model when both are present
gen_ai.request.modelModel nodeUsed when response model is absent
gen_ai.usage.input_tokensInput tokensCurrent GenAI semantic convention
gen_ai.usage.output_tokensOutput tokensCurrent GenAI semantic convention
gen_ai.usage.prompt_tokensInput tokensAccepted legacy alias
gen_ai.usage.completion_tokensOutput tokensAccepted legacy alias
gen_ai.usage.costSelf-reported USD costBadge extension; numeric, bounded, and labeled
gen_ai.tool.nameTool nodeUse a stable non-secret identifier; arguments and results are ignored
gen_ai.agent.nameAgent/role node (multi-agent hierarchy)Stored as a bounded agent:<display>~<hash> projection. The name must start with a letter and contain only letters, digits, _ or - — a name that doesn't is dropped, not cleaned up (see "Agent nodes do not appear" under Troubleshooting). At most 16 stored characters (the public read view cuts this to 12 — see "What Badge stores"); at most 8 distinct roles per run; supervisor→subagent edges come from real parent span structure
Span name retrievalRetrieval nodeOne of exactly seven accepted names: retrieve, retrieval, retriever, vector_search, vector.search, semantic_search, semantic.search. Anything else becomes unknown_operation
badge.response_sha256Answer-binding evidenceSHA-256 hex digest only; never the answer body
badge.run_idAgent-credential correlationRequired for every effective partition using an agent credential

Badge reads OpenInference, OpenLLMetry, LangSmith, Vercel, or other framework output only when it also emits the supported gen_ai.* keys. Framework-native prompt, message, content, llm.*, and ai.toolCall.name attributes are not remapped.

Unknown models are unpriced, never guessed as zero. A valid gen_ai.usage.cost remains self-reported telemetry. Badge estimates cost only when the exact model ID has a price effective on the run date and both token counts are valid nonnegative integers.

What Badge stores

Badge stores a bounded metadata projection: safe span, parent, and trace IDs; operation kind; model identifier; token counts; timestamps; safe tool identifier; optional numeric cost; run correlation; and answer hash. It does not persist prompt or completion content from OTLP.

What is stored is not what is published. A second, narrower projection is applied at read time for anyone who cannot edit the agent:

  • Model and tool digests are replaced by per-response ordinals (model:1, tool:1). Model IDs on Badge's vendored price allowlist stay verbatim.
  • An agent identity keeps its readable role name — case-folded and cut to 12 characters — with an ordinal in place of the digest: agent:researcher~2. This is the only caller-authored text on the public surface. It is bounded, not anonymised. Name nodes for the role, never for the customer, tenant, or internal system.
  • Token counts are floored to two significant figures; latencies and costs are rounded to nearest at two significant figures, so a published latency or cost can exceed the measured one. Owners get exact token counts and latencies; every stored cost is quantised to four significant figures.

Blueprint architecture and cost remain labeled self-reported or estimated. They do not change the run's composite score or fitness radar formula.

Architecture versions (where enabled)

Whether versioning is enabled is a server-side setting, exposed by the same public probe as "blueprint_versions": GET /api/v1/provenance/status.

On environments with versioning enabled, Badge assigns every traced run a content-addressed architecture version: two runs whose span graphs have the same structure and identities — the same roles, model identities, tool set, and call relations — share one version; a structural change mints the next one (v1, v2, …). Volatile signals (token counts, latency, cost, timestamps, retries of an existing path) never change the version. A version identifies structure and identities, not behaviour: prompts, sampling settings, and routing logic are invisible to it. Blueprint responses carry the version as blueprint_version (id, version_number, canonicalization_version); the field is null where versioning is disabled or the run predates it.

Reading the timeline. The agent's Evidence page lists its versions most recently seen first — so the version currently running sits at the top, even after a rollback to an older architecture (a rollback re-uses the existing version; it never mints a new one). Each entry shows when that version was first and last seen, how many traced runs are bound to it, and a summary of what changed against the version before it. Dates and counts cover the runs you can see: a run the owner keeps private moves nothing on the public timeline. The summary names a model only where the identity is one Badge recognises (gpt-4o-mini → gpt-5-mini); everywhere else it says model identity changed, because the comparison is over identifiers that were privacy-projected before storage — Badge can see that a model changed, not which model. A change to an agent node reads role renamed or replaced: the comparison cannot tell a rename from a replacement. An entry marked hashing rules updated is not an architecture change at all — it is the same architecture re-recorded after Badge changed how it canonicalises graphs. Signed out, or on someone else's agent, the same list appears without version numbers: versions are identified by their id, because the counter is minted across private runs too.

For agents with a signed manifest, the Evidence page's comparison panel also records declared vs observed against the architecture version it was computed on — reported, never enforced, and visible to the agent's owner and editors only. What it does and does not prove is covered in the Provenance FAQ.

Troubleshooting

404 from the OTLP endpoint

Blueprint/provenance processing is disabled. Check GET /api/v1/provenance/status or ask the environment operator.

Exporter sends to an added /v1/traces path

The generic OTLP endpoint setting was used. Configure the trace-specific setting with the complete Badge endpoint exactly as shown above.

Connection error on port 4317

The exporter is using OTLP/gRPC. Select OTLP/HTTP with protobuf or JSON.

401 Invalid or missing OTLP ingest token

Use the single-reveal credential created for the same agent. It remains usable until rotated, revoked, or made ineligible. Do not send a Badge API key to the receiver.

415 or 422

For 415, use application/x-protobuf or application/json. For 422 Malformed OTLP payload, make the body encoding and declared content type agree. Agent-credential batches also return 422 when a run ID is missing or a trace does not match the run's registered dispatch.

200 with accepted_spans: 0

The span IDs were already ingested, or the run reached its storage cap. Retries are idempotent.

Run completes but no Blueprint appears

Force-flush the exporter, confirm every partition carries the correct badge.run_id, and confirm at least one span has a supported model, tool, or retrieval signal.

Spans arrive but model or token data is absent

Inspect the exported attribute names. Framework-native llm.* fields are not automatically treated as gen_ai.*.

Tool names become opaque

This is unconditional and not a misconfiguration. Every accepted gen_ai.tool.name is stored as tool:<sha256[:16]>; there is no readable-tool allowlist and no identifier you can choose that stays readable. An anonymous reader sees less still — a per-response ordinal (tool:1), which is positional and not a stable key across responses.

Tool names disappear entirely

The value failed the ingest guard rather than being hashed. Use a short stable identifier, not arguments, URLs, credentials, or natural-language content. Vercel's ai.toolCall.name is not mapped today.

Agent nodes do not appear

The value failed the ingest guard rather than being shortened. gen_ai.agent.name must start with a letter and, in its first 16 characters, contain only letters, digits, _ or -. Dots, /, :, @, or a leading digit drop the name entirely and the span keeps its non-agent classification — research.agent yields no node, research_agent does. Internal spaces are fine (Math TutorMath_Tutor). At most 8 distinct roles per run are kept.

Cost shows unpriced

The exact model ID had no price effective on the run date, or one of the token counts was missing, invalid, or negative. Badge does not infer aliases or missing usage.

Trace is accepted but provenance stays unbound

Confirm that the trace ID matches the dispatched traceparent, the root span has the exact canonical response hash, and the agent echoes X-Badge-Trace-Id. Accepted late spans trigger recomputation; arrival after the initial evaluation does not by itself leave a run permanently unbound.