{
  "schema_version": "1.3.0",
  "slug": "what-structural-signals-indicate-a-silent-tool-call-span-loss-in-opentelemetry-genai-agent-telemetry",
  "title": "What structural signals indicate a silent tool-call span loss in OpenTelemetry GenAI agent telemetry",
  "date_of_record": "2026 November 13",
  "scope": "Applies to agents emitting spans under the OpenTelemetry GenAI semantic conventions (`gen_ai.operation.name`, `gen_ai.tool.name`, `gen_ai.agent.name`, `gen_ai.usage.*`) where tool invocations are instrumented as child spans of an agent span. Does not apply to pure LLM completion telemetry without tool dispatch, nor to systems where tool calls are recorded only as span events rather than spans.",
  "projections": {
    "unified_markdown_uri": "https://corpusfetch.com/c/what-structural-signals-indicate-a-silent-tool-call-span-loss-in-opentelemetry-genai-agent-telemetry.md",
    "method_python_slice_uri": "https://corpusfetch.com/c/what-structural-signals-indicate-a-silent-tool-call-span-loss-in-opentelemetry-genai-agent-telemetry.py",
    "remnant_warrant_slice_uri": "https://corpusfetch.com/c/what-structural-signals-indicate-a-silent-tool-call-span-loss-in-opentelemetry-genai-agent-telemetry.warrant.json"
  },
  "token_profile": {
    "full_markdown_tokens": 1231,
    "python_slice_tokens": 148,
    "warrant_slice_tokens": 220
  },
  "remnant_summary": {
    "core_distinction": "A tool call that *executes but is not represented as a span* is categorically different from a tool call that *fails and is represented as an error span*. The first is a telemetry-integrity failure; the second is a normal, observable outcome. The GenAI conventions make this boundary easy to cross silently because the agent span's `gen_ai.usage.*` and message...",
    "what_was_observed": "In a multi-agent orchestration deployment, agent spans were routinely emitted with `gen_ai.operation.name = \"invoke_agent\"` and a `gen_ai.agent.name`, but with zero child spans of `gen_ai.operation.name = \"execute_tool\"` despite the agent message history containing `tool_calls` entries with non-empty `id` and `name`. The tool executions had occurred — side effects were present in downstream systems — but the tracer c...",
    "condition_of_validity": "This diagnostic is valid only when the agent span is emitted *after* tool dispatch completes and the agent span is the direct parent of tool spans per the conventions. If the deployment uses span links instead of parent-child nesting (permitted for async tool dispatch), the child-count check must be replaced by a link-count check against `gen_ai.tool.call.id...",
    "decision_boundary": "Treat a zero-child agent span as a **telemetry loss** (not a no-tool turn) if and only if all three hold: (1) the agent span's message attributes contain at least one `tool_calls` entry, (2) the agent span duration exceeds the p50 no-tool agent duration for that agent name by more than one standard deviation, and (3) no span in the trace carries a matching `...",
    "operational_effect": "When the boundary is crossed, the correct response is to fail the trace-integrity check rather than the request, and to attach the observed call ids to the alert so the missing spans can be backfilled from the tool execution logs. Downstream cost and latency attribution must treat the agent span's duration as *inclusive of unaccounted tool time* until backfi..."
  },
  "matched_failure_symptoms": [
    "DOMAIN:EPISTEMIC_PROVENANCE_AND_FEDERATION_ROUTING"
  ],
  "composition_edges": {
    "primary_domain": "epistemic_provenance_and_federation_routing",
    "upstream_precondition_residuals": [
      "https://corpusfetch.com/c/according-to-what-precedence-hierarchy-must-an-instance-resolve-contradictory-directives-across-system-developer-and-user-tiers.md",
      "https://corpusfetch.com/c/how-should-an-instance-decide-that-a-stored-conclusion-has-gone-stale-without-a-new-observation.md"
    ],
    "downstream_consequence_residuals": [
      "https://corpusfetch.com/c/by-what-checkpoint-and-compaction-boundaries-must-an-instance-externalize-working-state-to-prevent-context-window-drift-and-truncation-amnesia.md",
      "https://corpusfetch.com/c/across-what-additive-schema-and-unknown-field-preservation-boundaries-must-an-instance-evolve-wire-contracts-to-prevent-rolling-deploy-deserialization-crashes.md"
    ],
    "co_occurring_sibling_residuals": [
      "https://corpusfetch.com/c/how-can-an-instance-capture-implicit-user-preferences-without-storing-private-data.md",
      "https://corpusfetch.com/c/how-can-an-instance-compress-long-reasoning-traces-into-binding-conclusions.md"
    ]
  },
  "empirical_verification_warrant": {
    "status": "AST_AND_INVARIANT_VERIFIED",
    "syntax_valid": true,
    "code_sha256": "042a52cb27ab6e38d9ac75e877d56194ce24463bba006223a7e8a38548340c8c",
    "verified_classes": [
      "ToolSpanLossError",
      "SpanSummary"
    ],
    "verified_functions": [
      "assert_tool_spans_present"
    ],
    "verified_functions_count": 1,
    "defensive_guards_count": 1,
    "raised_exceptions": [
      "ToolSpanLossError"
    ],
    "sample_fail_closed_invariants": [],
    "stdlib_dependencies": [
      "dataclasses"
    ],
    "observation_mode": "EMPIRICAL_BOUNDARY_CAPTURE",
    "zero_external_deps": true
  }
}
