Optimize Coval Trace Observability
Turn a working but thin Coval trace into a useful debugging artifact. Prefer to
inspect a proven Coval trace first. If
has launched an initial
asynchronous validation run that is still pending, use the waiting time to make
safe code-visible enrichment, then re-check the finished run before declaring
the optimization complete.
Read First
Load these references as needed:
../references/span-schema.md
for canonical spans, attributes, aliases, and guardrails
../references/agent-type-routing.md
for framework-specific trace boundaries
../references/coval-tracing-reference.md
for viewer/search behavior and ingestion limits
Phase 1: Inspect Current Trace Quality
Start from evidence, not assumptions.
- Find one recent traced simulation or conversation in Coval. Use the Coval
CLI/API or Trace Search instead of asking the user for a screenshot when
credentials are available.
- If the only candidate is an in-flight validation run from ,
start or continue a bounded CLI/API poll loop and do not block idly. While
waiting, inspect the code path and add only enrichment that is clearly safe
from the implementation.
- Inspect the trace viewer or exported trace dump once trace data exists.
- Classify the current trace:
- no trace
- trace exists but only root/provider spans
- STT/LLM/TTS spans exist but lack attributes
- tool spans missing
- parent/child structure is flat or misleading
- attributes are unsafe, oversized, or high-cardinality
- Check whether existing framework instrumentation should be enriched instead of duplicated.
Do not add manual duplicate spans for operations already emitted by Pipecat, LiveKit, Vapi, or an existing OTel integration unless the existing span cannot be enriched.
Phase 1b: Discover Business Events Already In The Code
Before deciding what to add,
grep the agent code for business-event surface
area the customer already implements but isn't tracing. Search for terms like
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
.
Each match is a candidate for a
span or
span
with a numeric attribute that can later become a customer-signal metric.
This is the most common missed coverage layer: the customer's protocol already
defines meaningful business events that never make it into traces because the
first pass only instrumented the audio/LLM pipeline.
Propose one span per distinct business event with at least one numeric
attribute (cart total, item count, payment amount, escalation level, etc.).
Do not wait for the customer to ask "is that all?" before adding these.
Phase 2: Add Coval-Native Span Coverage
Prioritize spans that make Coval trace UI, built-in trace metrics, and custom trace metrics more useful:
- : full call/session root
- : one user/assistant exchange when the framework exposes a turn boundary
- : final speech recognition result
- : each STT provider attempt or fallback
- : model call
- : synthesis call
- : tool/function execution
- : speech activity decisions when relevant
- or : only when they help diagnose routing/audio issues
Keep span names stable and low-cardinality. Put IDs, provider names, endpoint names, and dynamic details in attributes.
Match the public span naming convention before adding custom business spans:
canonical names get semantic colors, labels, and built-in trace metric support.
Prefer OTel span events over new spans for moment-in-time annotations.
A span event (
span.add_event("simulation_id_received", {...})
) is a cheap
timestamped marker on an existing span — it does not bloat the span count, does
not affect trace metrics, and gives the trace viewer a visible flag on the
parent timeline. Use events for milestones like
,
,
,
,
,
, and
on the
root or
the relevant
. Reserve full spans for things with non-trivial duration or
parent/child structure.
Phase 3: Add High-Value Attributes
Use the canonical attributes from
../references/span-schema.md
.
Minimum valuable set:
- : , , when available
- : , , , error status when a provider fails
- : , ,
gen_ai.usage.input_tokens
, gen_ai.usage.output_tokens
, model/provider metadata when available
- : , provider/voice metadata when safe
- : , , if safe and bounded, , numeric , numeric
tool.dependency_unavailable
, when applicable
- : , , numeric , numeric
workflow.dependency_blocked
, numeric when the session boundary is available
- custom spans: one numerical attribute that can become a custom trace metric, such as , , , , or
Set OTel status to
on failing provider/tool/API spans. Coval custom trace metrics can calculate
and
from span status.
Also emit numeric
/
flags for important rates. Some public metric
creation APIs require a numeric
;
over these flags
preserves the rate while still working in those environments.
Phase 4: Protect Customers
Before committing enrichment, remove or bound:
- API keys, tokens, passwords, session cookies, account secrets, and credentials
- raw audio blobs or base64 audio
- full prompts/responses when they may contain PII
- unbounded transcripts in custom attributes unrelated to
- high-cardinality span names
- duplicated successful export retries
Prefer summaries and counts:
workflow.dependency_blocked
Phase 5: Verify Improved Value
After changes:
- Run one representative simulation or conversation through the Coval CLI/API,
or reuse the in-flight validation run if it exercises the changed code.
- Poll through the CLI/API until the run finishes and trace data appears. While
it is pending, prepare candidate metrics or documentation notes instead of
waiting idle.
- Open the Coval trace viewer.
- Confirm the trace has meaningful hierarchy and expected span colors.
- Check Trace Search can filter by span name, status, duration, provider, or attributes.
- If new numerical attributes were added, run to create at least one metric against them after the span/attribute is visible in real trace data.
Report before/after differences in concrete terms, such as span count, new span names, new attributes, and the specific debugging question the trace can now answer.