series = a field guide to the Phoenix tracing data model
Spans all the way down
Phoenix ingests OpenTelemetry traces and shows you sessions, turns, traces, and spans. Exactly one of those four things actually exists. This series is about what that fact buys us, what it costs us, and how the interface should be honest about it.
Here is the entire data model of OpenTelemetry tracing, and therefore the entire data
model that arrives at Phoenix over the wire: a span is a named, timed operation
with a bag of key–value attributes and three identifiers — its own
span_id, an optional parent_id, and a trace_id
shared with other spans. That's it. There is no trace record on the wire. There is no
session record anywhere. There is certainly no "turn."
Everything above the span is a query. A trace is
GROUP BY trace_id. A tree is a recursive join on
parent_id. A session is GROUP BY an attribute
(session.id) that the application promised to stamp on its spans. A
turn is a styling decision applied to a trace's root span. None of this is a
complaint — deriving structure from flat, immutable records is a fine architecture, and
Part 2 argues it's mostly the right one. But an interface designed as if traces and
sessions were sturdy first-class objects will keep tripping over the places where they
aren't, and ours does, in ways this series will point at specifically.
The nine records above never change — only the query does. That's the mental model this
series keeps returning to: the span is the only object; trace, waterfall, and
session are projections. When a projection looks like a container, it's worth
asking what happens at its edges: when the root span never arrives, when two spans
disagree about session.id, when a trace is still growing while you look at
it. Those edge cases are where Phoenix's interface currently wobbles, and they're all
downstream of treating a projection like an object.
The series
a companion series
The Second Write Path
This series is about the facts Phoenix stores. Its companion is about the judgments written on top of them — the annotation model and its identity key, evaluators as stored server-side objects, the construction UI, and the open design questions around online evals, scopes, and read amplification. Start here if you've read the model; read that one if you're building the evaluation layer.
Audience note. This is written for people who are comfortable with databases, distributed systems, and reading a schema, but new to AI observability. It assumes no familiarity with OpenTelemetry, LangSmith, or Phoenix itself. Where a claim is about Phoenix's actual behavior rather than its documentation, it cites the code — file and line — so you can check.