Repository navigation
feat(tracing): write the span attributes the failure checks read - #555
mohammadatallah-scale wants to merge 17 commits into
Conversation
Offline failure checks read sgp.agent.* attributes the agent declares on its spans. FailureCheckSpec validates the root span declarations on construction and renders them as flat dotted keys holding native JSON values, which the SGP processor ships verbatim as span metadata. output_name, verification_result and escalates write the per-span attributes. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The span store keeps metadata in a ClickHouse JSON column, where a schema object spreads into many dynamic paths whose keys can collide after dot-splitting. FailureCheckSpec still takes a JSON object and validates it, then renders sgp.agent.output_schema as a JSON string. Every other attribute stays a native value. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
output_schema is a mutable dict on a frozen spec, so an edit after construction skipped the checks construction applies and could write NaN or invalid JSON text. attributes() now runs the same check before writing the schema, so an edited schema fails with the error construction raises. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
P3 Refuted: |
adk.tracing.span yields None when trace_id is empty or the span fails to start, so the example reading root.data raised AttributeError on that path. It now guards the span the way the tutorial's acp.py does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Only step_budget, stop_reason and prompt_version errors were checked for the attribute they name, so relabelling escalation_channels as quote_arguments still passed. Every root field and VerificationRule now asserts the name its error starts with. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
P3 Follow-up: the attribute-naming pins landed in 815dad0, and each label swap above now fails 2 to 11 tests. The non-string key coercion is left open because fixing it changes behavior the scale-gp-beta port must match, so both helpers need it together. |
The depth was an inline number, so a reader could not tell what it controls. It is now a named class constant. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A path like send_email.to.cc was rejected with a message that did not say why. Tool names cannot contain dots, so an entry is a tool and one top-level argument, and the error now says nested argument paths are not supported. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
escalates("") failed with a message about a verification span id, which did
not name the attribute being written. The message now starts with escalates,
as the other validation errors start with their attribute.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
JSON writes every object key as a string, so the encoder quietly turned an
int, bool, float or None key into text and let {1: "a", "1": "b"} collapse
into one entry. Any non-string mapping key in the schema is now rejected, at
construction and again when attributes render.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A successful Claude Code or Codex tool call reports no is_error, so the failure checks could not tell its span was a tool call. Every harness tool span now carries gen_ai.operation.name=execute_tool and gen_ai.tool.name. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The hooks wrote str(result), a Python repr the failure checks cannot decode. Objects are now written as JSON text, strings stay as they are, and str is the fallback only when the result cannot be serialized. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The escalation check reads a list of span ids, so escalates() now takes several and writes them as a list. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The span context managers caught only Exception, so a cancelled or interrupted call ended its span as SUCCESS. They now record any BaseException and re-raise it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The LiteLLM completion spans and the OpenAI Agents streaming model span now carry gen_ai.request.model, the attribute the failure checks read as the model a call was made to. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
otel_attributes turns the helpers' data into OpenTelemetry attribute values, writing the verification rules and any other object as JSON text, and otel_span_id gives the id escalates takes for an OpenTelemetry span. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Important
Pending Mohammad's self-review. This note is removed by a human, not automation.
Offline failure checks read attributes an agent declares on its spans, and AgentEx agents hand-build every key with nothing checking the values (OVE-1375). This adds a helper that writes and validates them from one spec, ported to scale-gp-beta in scaleapi/sgp-dev-python-staging#10.
data.otel_attributesturns any of these into span attributes, writing the verification rules as JSON text, andotel_span_idnames a span toescalates.Merge waits until public scale-agentex-python merges reopen after the vulnerability work, about end of November. Until then the Dogfood agent carries its own copy of the helper, as the end-to-end harness does.
Test plan
🤖 Generated with Claude Code


Confidence Score: 5/5
The PR appears safe to merge; no actionable issues remain from this review.Summary
This PR adds validated attributes for offline failure checks and records tool names, model names, JSON results, and interrupted calls on spans.
Diagram
%%{init: {'theme': 'neutral'}}%% flowchart LR A[FailureCheckSpec and per-span helpers] --> B[Attribute dictionary] B --> C[AgentEx span data] C --> D[SGP metadata] B --> E[otel_attributes] E --> F[OpenTelemetry span attributes] G[OpenTelemetry span] --> H[otel_span_id] H --> I[escalates] I --> BReviews (7) · Last reviewed commit: "feat(tracing): write failure-check attri..." · Reviewed by Greptile