tessary.call_site.id is the span attribute that names which one a span belongs to.
It is the only thing Tessary attributes a span to a call site from. There is no inference from file path, span name, model id, or prompt shape, because guessing would mis-attribute production traffic and every mis-attribution is silent.
Why the tag is required rather than optional
Classifiers work by comparison. A classifier fits a baseline for a call site and then evaluates new traces against it, so it needs to know which traffic is comparable to which. Two model calls in one service can differ by an order of magnitude in length, cost, and failure rate and still both be healthy; pooled together they produce a baseline that describes neither. The tag is how Tessary knows which is which. That has three consequences you can observe:- A span with no
tessary.call_site.idis ingested, stored, and queryable, and nothing scoped to a call site reads it. - The connect gate opens on a tagged span, not on any span. A project can have thousands of spans and still be stuck on the gate.
- The broader milestone ladder does advance on untagged traffic, which is why a project can read
fittingwhile the gate is still closed. Confirm traces are arriving covers the difference.
What counts as one call site
Call sites defines the unit: one combination of intent, system prompt, and output schema, rather than one line of code or one file. Two rules follow from that definition when you decide what to tag:- Follow the dispatch. Where a single location selects its prompt or schema from a registry keyed on a parameter, emit one call site per branch. A handler that makes three different model calls is three call sites, and one tag on the handler collapses them into a baseline that describes none of them.
- Do not over-split. A parameter that varies only content, such as the end user’s text or a temperature, is the same call site.
The last three usually have no span around them already, and they are often the highest-risk calls in a repository precisely because nothing watches them. Wrapping one is more work than tagging an existing span. Skipping it is how a failure mode stays invisible.
Choosing an id that survives
The id names what the call produces. Keep it short and factual, and leave transport descriptors such asstreaming, async, or cached out of it: they describe how the call runs, not what it is for.
A dotted namespace groups a feature’s calls and is the default worth taking:
snake_case is fine for a handful of call sites. Do not mix both shapes in one repository.
If your repository already carries an instrumentation manifest at .tessary/pipeline/instrumentation.yaml, read it first and treat the ids in it as fixed.
Where the attribute goes in code
Set it on the span that covers the model call, with a literal value.1
Find or open the span that covers the call
If the call already runs inside a span, use that one. If it does not, open a span with the tracer the repository already configures. Never construct a second
TracerProvider: a span on a provider the Tessary exporter is not registered on is never exported, so the tag looks correct in code and nothing arrives.2
Set the attribute
3
Run the code and check the connect screen
A tag becomes telemetry only when the code runs.
The connect gate opens on its own once the first tagged span lands. On a project already past the gate, the call site appears once traffic carrying its id arrives.
Four rules that are not negotiable
- The key is
tessary.call_site.id, dotted. An underscore variant such astessary.call_site_idis never read. The span looks tagged and resolves to nothing. - The value is a literal. Never an f-string, a variable, or an enum lookup. A tag computed at runtime cannot be traced back to the code that produced it.
- Tag the span that covers the model call, not a parent request or handler span.
- Tag only the call sites you meant to tag. An unwanted call site is easier to leave out than to retire.
tessary.call_site.id is also the only tessary.* attribute Tessary reads. Session identity goes in session.id, the end user in user.id, nesting is derived from the span’s parent, the call’s kind goes in gen_ai.operation.name, and a failure goes in the span status. Span requirements lists the full vocabulary and the names that have no reader.
When you cannot edit the code
Spans that come from software you do not control can still be tagged one layer out, in an OpenTelemetry Collectortransform processor. The rules above do not change: the call site is still named explicitly, with a literal, on the span that covers the model call.
Related pages
Call sites
What a call site is, how a span is attributed to one, and what an untagged span still contributes.
Instrument your agent
The whole task, from the connect screen to a tagged span landing.
Instrumentation troubleshooting
What to do when spans arrive untagged, or the tag is in and nothing changes.
