# Tracing Attribute Reference

Provon accepts standard OpenTelemetry spans and projects recognized GenAI attributes into trace,
conversation, user, cost, and diagnostic read models. Unknown OTel attributes remain available on
the span when payload retention allows it.

Use this page as the field reference. For boundary and topology decisions, read
[Trace model and instrumentation](./tracing-model.md).

## Core OpenTelemetry Fields

Every span needs the normal OTLP identity and timing fields:

| OTLP field          | Purpose                                                     |
| ------------------- | ----------------------------------------------------------- |
| `traceId`           | Groups spans into one bounded execution                     |
| `spanId`            | Identifies one operation                                    |
| `parentSpanId`      | Connects a child to a parent inside the same trace          |
| `name`              | Stable, low-cardinality operation name                      |
| `kind`              | `INTERNAL`, `SERVER`, `CLIENT`, `PRODUCER`, or `CONSUMER`   |
| start and end time  | Orders work and calculates duration                         |
| status              | `UNSET`, `OK`, or `ERROR`                                   |
| attributes          | Operation evidence and searchable dimensions                |
| resource attributes | Workload identity such as service, version, and environment |
| events              | Point-in-time facts such as recorded exceptions             |

Provon normalizes timestamps to Unix milliseconds after decoding. Preserve stable trace and span
IDs across exporter retries.

## Resource Attributes

Set these once on the OTel resource:

| Attribute                     | Requirement | Use                                                           |
| ----------------------------- | ----------- | ------------------------------------------------------------- |
| `service.name`                | Recommended | Stable workload or agent-service identity                     |
| `service.version`             | Optional    | Deployed application version                                  |
| `deployment.environment.name` | Recommended | Environment such as `production`, `staging`, or `development` |

Provon also recognizes `deployment.environment` and `environment` on resource or span attributes
when projecting environment views. Prefer `deployment.environment.name` for new instrumentation.

## Execution And Grouping

| Attribute                  | Type   | Use                                                            |
| -------------------------- | ------ | -------------------------------------------------------------- |
| `gen_ai.operation.name`    | string | Classifies inference, tool, retrieval, agent, or workflow work |
| `gen_ai.conversation.id`   | string | Groups related traces across turns or independent agent runs   |
| `gen_ai.agent.id`          | string | Stable participant identity                                    |
| `gen_ai.agent.name`        | string | Human-readable participant name                                |
| `gen_ai.agent.version`     | string | Participant behavior or release version                        |
| `gen_ai.agent.description` | string | Optional participant description                               |
| `gen_ai.workflow.name`     | string | Stable workflow or orchestration name                          |

### Operation Mapping

Provon maps recognized operation values to these span types:

| `gen_ai.operation.name` | Projected type    |
| ----------------------- | ----------------- |
| `embeddings`            | `embeddings`      |
| `retrieval`             | `retrieval`       |
| `execute_tool`          | `execute_tool`    |
| `create_agent`          | `create_agent`    |
| `invoke_agent`          | `invoke_agent`    |
| `invoke_workflow`       | `invoke_workflow` |
| Other values            | `inference`       |

Use current OpenTelemetry GenAI operation names. Do not encode operation type only in the span name.

### Conversation Aliases

New instrumentation should use `gen_ai.conversation.id`. The normalizer also recognizes:

```text
conversation.id
conversation_id
provon.conversation_id
thread.id
thread_id
```

If none is present, CLI diagnosis falls back to the trace ID as the trajectory boundary. That keeps
a trace diagnosable by itself but cannot reconstruct cross-trace conversation evidence.

## User Attributes

| Attribute        | Type     | Use                                       |
| ---------------- | -------- | ----------------------------------------- |
| `user.id`        | string   | Opaque observed application-user ID       |
| `user.hash`      | string   | Stable privacy-preserving user identity   |
| `user.name`      | string   | Optional display name                     |
| `user.full_name` | string   | Optional full name                        |
| `user.email`     | string   | Optional email, subject to privacy policy |
| `user.roles`     | string[] | Optional application roles                |

These describe users observed in agent activity, not Provon workspace members. Prefer opaque IDs
and send personal data only when the deployment is allowed to retain it.

## Model Request And Response

| Attribute                             | Type     |
| ------------------------------------- | -------- |
| `gen_ai.provider.name`                | string   |
| `gen_ai.request.model`                | string   |
| `gen_ai.request.choice.count`         | integer  |
| `gen_ai.request.seed`                 | integer  |
| `gen_ai.request.stream`               | boolean  |
| `gen_ai.request.frequency_penalty`    | number   |
| `gen_ai.request.max_tokens`           | integer  |
| `gen_ai.request.presence_penalty`     | number   |
| `gen_ai.request.stop_sequences`       | string[] |
| `gen_ai.request.temperature`          | number   |
| `gen_ai.request.top_k`                | number   |
| `gen_ai.request.top_p`                | number   |
| `gen_ai.request.encoding_formats`     | string[] |
| `gen_ai.response.id`                  | string   |
| `gen_ai.response.model`               | string   |
| `gen_ai.response.finish_reasons`      | string[] |
| `gen_ai.response.time_to_first_chunk` | number   |
| `gen_ai.output.type`                  | string   |
| `server.address`                      | string   |
| `server.port`                         | integer  |

Provider and model identity power trace filters and cost lookup. Prefer the actual response model
when a provider returns one.

## Messages And Instructions

| Attribute                    | Type            | Use                                |
| ---------------------------- | --------------- | ---------------------------------- |
| `gen_ai.input.messages`      | structured JSON | Input messages for the operation   |
| `gen_ai.output.messages`     | structured JSON | Output messages from the operation |
| `gen_ai.system_instructions` | structured JSON | System or developer instructions   |
| `gen_ai.tool.definitions`    | structured JSON | Tools made available to the model  |

Use role-labeled message objects where possible:

```json
[
  {
    "role": "user",
    "content": "Verify the deployment and report the result."
  }
]
```

The root agent span should expose the bounded run's user goal and terminal output. Child inference
spans should contain the messages they actually consumed and produced.

## Tool Attributes

| Attribute                    | Type            |
| ---------------------------- | --------------- |
| `gen_ai.tool.name`           | string          |
| `gen_ai.tool.type`           | string          |
| `gen_ai.tool.description`    | string          |
| `gen_ai.tool.call.id`        | string          |
| `gen_ai.tool.call.arguments` | structured JSON |
| `gen_ai.tool.call.result`    | structured JSON |

Use one `execute_tool` span per attempt. Keep failed attempts and their results, set span status
`ERROR`, and add `error.type`. Do not replace a failed attempt with a later successful result.

## Retrieval And Embeddings

| Attribute                           | Type            |
| ----------------------------------- | --------------- |
| `gen_ai.data_source.id`             | string          |
| `gen_ai.retrieval.query.text`       | string          |
| `gen_ai.retrieval.documents`        | structured JSON |
| `gen_ai.embeddings.dimension.count` | integer         |

Bound retrieved documents before export. A stable document reference and the decisive excerpt are
usually more useful than copying an entire corpus into one span.

## Usage And Cost

| Attribute                                  | Type    |
| ------------------------------------------ | ------- |
| `gen_ai.usage.input_tokens`                | integer |
| `gen_ai.usage.output_tokens`               | integer |
| `gen_ai.usage.reasoning.output_tokens`     | integer |
| `gen_ai.usage.cache_creation.input_tokens` | integer |
| `gen_ai.usage.cache_read.input_tokens`     | integer |

Provon derives cost from provider, model, and usage when the model matches its pricing catalog.
Applications can provide explicit cost using these compatibility attributes:

```text
gen_ai.usage.cost.input
gen_ai.usage.cost.output
gen_ai.usage.cost.reasoning_output
gen_ai.usage.cost.cache_creation_input
gen_ai.usage.cost.cache_read_input
gen_ai.usage.cost.total
```

The equivalent `gen_ai.cost.*` names are also accepted, as are `llm.usage.cost` and `cost_usd` for a
provided total. Values are USD numbers. Provided cost takes precedence over catalog calculation.

## Errors

For a failed operation:

1. Set span status to `ERROR`.
2. Set `error.type` to a stable category.
3. Record the exception event when the SDK supports it.
4. Keep the failed provider or tool result.
5. Represent recovery as a later span.

Error text without error status can remain visible but may be missed by error filters and
deterministic diagnostic signals.

## Structured Values

OTLP attributes can carry primitives, arrays, and key-value lists. Provon preserves bounded
JSON-friendly structures for messages, tools, definitions, and retrieval documents.

When an SDK cannot emit a structured attribute, JSON-encode it:

```ts
span.setAttribute(
  'gen_ai.tool.call.result',
  JSON.stringify({ status: 'failed', reason: 'permission_denied' }),
);
```

Provon parses valid JSON-looking strings for recognized structured fields. Invalid JSON remains a
string and loses the expected structured projection.

## Minimum Evidence Sets

| Goal        | Minimum fields                                                                    |
| ----------- | --------------------------------------------------------------------------------- |
| Visible     | Core IDs, timestamps, names, and parent relationships                             |
| Searchable  | `service.name`, operation, conversation, user, agent, model, environment, status  |
| Diagnosable | Goal, ordered messages, tool inputs/results, errors, retries, and terminal output |

Do not emit derived conclusions such as `hallucinated=true` as execution facts. Provon derives
diagnostic labels from objective evidence and publishes them as Findings.

## Related Docs

- [Tracing quickstart](./tracing-quickstart.md)
- [Trace model and instrumentation](./tracing-model.md)
- [Diagnosis-ready tracing](./tracing-best-practices.md)
- [Multi-agent and distributed tracing](./tracing-multi-agent.md)
- [OpenTelemetry setup](./opentelemetry.md)
- [Production tracing](./tracing-production.md)
