# `Otel.Trace.TraceState`
[🔗](https://github.com/yangbancode/otel/blob/main/lib/otel/trace/tracestate.ex#L1)

W3C Trace Context `tracestate` field (spec §3.3).

An opaque, immutable, ordered list of vendor-specific key/value
pairs propagated alongside the `traceparent` header across tracing
systems. Values are opaque to OpenTelemetry — each vendor owns
its own key's semantics.

## Public API

| Function | Role |
|---|---|
| `get/2`, `add/3`, `update/3`, `delete/2` | **Application** (OTel API MUST) |
| `encode/1` | **Application** (W3C header serialization) |
| `decode/1` | **Application** (W3C header parsing) |
| `valid_key?/1`, `valid_value?/1` | **Application** (W3C format predicate) |
| `new/0`, `empty?/1` | **Application** (Convenience) |

## References

- W3C Trace Context: `w3c-trace-context/spec/20-http_request_header_format.md`
- OTel Trace API: `opentelemetry-specification/specification/trace/api.md`

# `key`

```elixir
@type key() :: String.t()
```

A W3C TraceState key (spec §3.3.1.3.1, Level 2).

Must begin with a lowercase letter (`a-z`) or digit (`0-9`),
followed by up to 255 characters from
`[a-z0-9_\-*/@]` (total ≤256 characters).

Invalid keys are silently dropped by mutating operations and
decoders.

# `t`

```elixir
@opaque t()
```

An opaque W3C TraceState (spec §3.3.1.2 `list`).

External code must use the public API (`new/0`, `add/3`,
`update/3`, `delete/2`, `decode/1`) to construct or mutate. The
internal representation (an ordered `[{key, value}]` list, newest
at the front per W3C §3.5 Mutating rules) is not part of the
public contract.

# `value`

```elixir
@type value() :: String.t()
```

A W3C TraceState value (spec §3.3.1.3.2).

Printable ASCII (0x20–0x7E) excluding `,` (0x2C) and `=` (0x3D),
1–256 characters; the last character MUST NOT be a space.

Invalid values are silently dropped by mutating operations and
decoders.

# `add`

```elixir
@spec add(trace_state :: t(), key :: key(), value :: value()) :: t()
```

**Application** (OTel API MUST) — "Add a new key/value pair"
(`trace/api.md` TraceState).

Prepends a new `{key, value}` entry per W3C §3.5 Mutating:
"The new key/value pair SHOULD be added to the beginning of the
list."

Returns the state unchanged when:

- the key violates W3C §3.3.1.3.1 format,
- the value violates W3C §3.3.1.3.2 format, or
- `key` is already present. W3C §3.5 requires that "Adding a
  key/value pair MUST NOT result in the same key being present
  multiple times" — for "update-or-add" semantics use `update/3`.

If adding would push the list past 32 entries, the right-most
(oldest) entry is dropped per W3C §3.3.1.1: "If adding an entry
would cause the `tracestate` list to contain more than 32
`list-members` the right-most `list-member` should be removed
from the list."

# `decode`

```elixir
@spec decode(header :: String.t()) :: t()
```

**Application** (W3C header parsing) — §3.3.1 `tracestate
Header Field Values`.

Splits a W3C `tracestate` header value into `{key, value}`
entries, collapsing duplicate keys to the last occurrence.

This function performs **parsing only** — it does not validate
individual key/value format (W3C §3.3.1.6 grants parsers
discretion on partially-parsed pairs) nor enforce the 32
list-member cap (W3C §3.3.1.1 is an "adding" rule). Validation
is applied at mutation time by `add/3` / `update/3` per
OTel api.md L294-L295. Pairs without `=` raise `MatchError`.

Used by `Otel.Propagator.TextMap.TraceContext` when
extracting incoming requests.

# `delete`

```elixir
@spec delete(trace_state :: t(), key :: key()) :: t()
```

**Application** (OTel API MUST) — "Delete a key/value pair"
(`trace/api.md` TraceState).

Removes the entry for `key`, if present. No-op when `key` is
absent.

# `empty?`

```elixir
@spec empty?(trace_state :: t()) :: boolean()
```

**Application** (Convenience) — empty-state predicate.

Returns whether the TraceState has no entries.

Used by `Otel.Propagator.TextMap.TraceContext` to skip
injecting an empty `tracestate` header (W3C §3.3.1 L275:
"SHOULD avoid sending [empty headers]").

# `encode`

```elixir
@spec encode(trace_state :: t()) :: String.t()
```

**Application** (W3C header serialization) — §3.3.1.4 Combined
Header Value.

Serializes to a W3C `tracestate` header value. Returns `""` for
an empty state.

Used by `Otel.Propagator.TextMap.TraceContext` when injecting
outgoing requests.

# `get`

```elixir
@spec get(trace_state :: t(), key :: key()) :: value()
```

**Application** (OTel API MUST) — "Get value" (`trace/api.md`
TraceState).

Returns the value associated with `key`, or `""` (empty string)
when the key is absent.

Because W3C §3.3.1.3.2 forbids empty values, a well-formed state
cannot contain one — the empty-string return reliably signals
"not found".

# `new`

```elixir
@spec new(opts :: map()) :: t()
```

**Application** (Convenience) — build a TraceState. Preferred
over `%TraceState{}` at external call sites because `t/0` is
opaque.

# `update`

```elixir
@spec update(trace_state :: t(), key :: key(), value :: value()) :: t()
```

**Application** (OTel API MUST) — "Update an existing value"
(`trace/api.md` TraceState).

Removes the existing entry for `key` and prepends a new entry
with `value`. Per W3C §3.5: "Modified keys MUST be moved to the
beginning (left) of the list."

If `key` is not already present, the behaviour is equivalent to
`add/3`, including the 32-member cap (W3C §3.3.1.1) — the
right-most entry is dropped to make room.

Returns the state unchanged when the key or value is invalid per
W3C §3.3.1.3.1 / §3.3.1.3.2.

# `valid_key?`

```elixir
@spec valid_key?(key :: term()) :: boolean()
```

**Application** (W3C format predicate) — key (§3.3.1.3.1).

Returns whether `key` conforms to the W3C TraceState key format.
See `t:key/0` for the grammar. Returns `false` for any non-binary
input.

# `valid_value?`

```elixir
@spec valid_value?(value :: term()) :: boolean()
```

**Application** (W3C format predicate) — value (§3.3.1.3.2).

Returns whether `value` conforms to the W3C TraceState value
format. See `t:value/0` for the grammar. Returns `false` for any
non-binary input.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
