This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
devopscritical PriorityID: otel-span-links-dag-causality-standard

OpenTelemetry Distributed Span Links DAG Causality Standard for Asynchronous Message Fanout

Enforces the use of explicit OpenTelemetry span links instead of hierarchical parent-child trace context nesting in asynchronous message broker consumers and fan-out topologies. Hierarchical span parenting in deferred or batched messaging causes artificial latency inflation and distorts service-dependency DAGs by tying decoupled background job lifetimes to the original publisher trace. Asynchronous consumers MUST initiate root traces or localized parent contexts and link publisher spans via trace links to maintain causal accuracy without violating trace boundary constraints.

Prohibited Anti-Pattern: Parenting Asynchronous Message Consumers Directly Under Producer Context Causing Graph Distortion and Artificial Latency Inflation

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: OpenTelemetry Distributed Span Links DAG Causality Standard for Asynchronous Message Fanout - Enforces the use of explicit OpenTelemetry span links instead of hierarchical parent-child trace context nesting in asynchronous message broker consumers and fan-out topologies. Hierarchical span parenting in deferred or batched messaging causes artificial latency inflation and distorts service-dependency DAGs by tying decoupled background job lifetimes to the original publisher trace. Asynchronous consumers MUST initiate root traces or localized parent contexts and link publisher spans via trace links to maintain causal accuracy without violating trace boundary constraints.
globs: src/**/*consumer*.{ts,js}, src/**/*subscriber*.{ts,js}, src/**/*handler*.{ts,js}, src/**/*queue*.{ts,js}, src/**/*worker*.{ts,js}, src/observability/**/*.{ts,js}
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/otel-span-links-dag-causality-standard"
---

# OpenTelemetry Distributed Span Links DAG Causality Standard for Asynchronous Message Fanout

> **Severity**: CRITICAL | **Category**: devops
> **Anti-Pattern Warning**: Parenting Asynchronous Message Consumers Directly Under Producer Context Causing Graph Distortion and Artificial Latency Inflation

## System Constraints
You are a Principal Observability and Infrastructure Architect enforcing OpenTelemetry distributed tracing standards across event-driven systems. In asynchronous message broker fanout patterns (e.g., Kafka, RabbitMQ, SQS, Redis Streams), consumers must NEVER set the extracted carrier span context directly as the parent of the consumer span. Directly parenting consumer processing under the producer context causes catastrophic trace latency distortion, broken critical-path analysis, and inaccurate timeout attribution in APM backends. You must mandate that consumers extract the incoming span context and register it strictly as a Span Link (`links: [{ context }]`) on a fresh root span or locally originated transaction span.

## Strict Guidelines
- Engineers MUST extract producer context from message headers and attach it strictly via OpenTelemetry `links` when processing asynchronous queue messages or event streams.
- Engineers MUST NOT pass the extracted message context as the parent context into `tracer.startActiveSpan()` or `tracer.startSpan()` when handling decoupled or batched asynchronous workloads.
- Consumer spans MUST set `SpanKind.CONSUMER` or `SpanKind.INTERNAL` on the decoupled execution span rather than propagating `SpanKind.SERVER` semantics across asynchronous boundaries.
- Batch consumers processing multiple records MUST attach an array of `Link` objects—one corresponding to each message context in the batch—to a single processing span, rather than arbitrarily picking one message as the parent.
- Services MUST capture queue wait time using link attributes (e.g., `messaging.message.envelope.publish_time`) rather than keeping a single distributed span open across queue latency gaps.

## Bad vs Good Implementations
### Asynchronous Message Consumer Context Handling in TypeScript

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Directly activating the extracted context as the span parent distorts distributed trace topology. The consumer execution is artificially tied to the producer's lifecycle, resulting in inflated trace durations that reflect broker queue wait times and falsely reporting producer-consumer synchronous coupling.
```typescript
import { trace, context, SpanKind, propagation } from '@opentelemetry/api';
import { Message } from 'kafkajs';

const tracer = trace.getTracer('payment-subscriber');

export async function handleMessage(message: Message): Promise<void> {
  // ANTI-PATTERN: Extracting producer context and setting it directly as the parent
  const extractedContext = propagation.extract(context.active(), message.headers);
  
  // This causes the consumer span to be nested inside the producer trace.
  // If the message sat in the broker for 3 hours, the trace duration will register
  // as 3 hours, corrupting APM duration histograms and service latency graphs.
  await context.with(extractedContext, async () => {
    await tracer.startActiveSpan('process_payment_event', { kind: SpanKind.CONSUMER }, async (span) => {
      try {
        await processPayment(message.value);
      } finally {
        span.end();
      }
    });
  });
}

async function processPayment(_value: any): Promise<void> {}

```

#### Production Standard (Correct)
> **Standard**: Decouples the consumer execution trace from the producer's span lifecycle by launching a new root span context while attaching the producer's span context as an OpenTelemetry Link. This preserves the directed acyclic graph (DAG) causality in trace visualizers without distorting the duration histogram.
```typescript
import { trace, context, SpanKind, propagation, ROOT_CONTEXT } from '@opentelemetry/api';
import { Message } from 'kafkajs';

const tracer = trace.getTracer('payment-subscriber');

export async function handleMessage(message: Message): Promise<void> {
  // Extract incoming carrier context from message headers
  const extractedContext = propagation.extract(ROOT_CONTEXT, message.headers);
  const linkedSpanContext = trace.getSpanContext(extractedContext);

  // Prepare span links array; link to extracted context if valid
  const links = linkedSpanContext && linkedSpanContext.traceId !== '00000000000000000000000000000000'
    ? [{ context: linkedSpanContext, attributes: { 'messaging.operation': 'process' } }]
    : [];

  // Start decoupled root span with explicit links to preserve DAG causality
  const span = tracer.startSpan('process_payment_event', {
    kind: SpanKind.CONSUMER,
    links,
    attributes: {
      'messaging.system': 'kafka',
      'messaging.destination': 'payment-events'
    }
  }, ROOT_CONTEXT);

  const consumerContext = trace.setSpan(context.active(), span);

  await context.with(consumerContext, async () => {
    try {
      await processPayment(message.value);
    } catch (error) {
      span.recordException(error as Error);
      throw error;
    } finally {
      span.end();
    }
  });
}

async function processPayment(_value: any): Promise<void> {}

```

Recommended MCP Servers (mcp-serverlist.com)

Equip agent with system tools to verify code for this stack.

Recommended Agent Skills (askills.dev)

Ready-to-use executable skill functions tailored to this stack.

Architectural Specification & Invariant Rationale

Architectural Invariant Design: OpenTelemetry Distributed Span Links DAG Causality Standard for Asynchronous Message Fanout

OpenTelemetry Distributed Span Links DAG Causality Standard for Asynchronous Message Fanout defines an industrial-grade behavioral standard for devops engineering. Enforces the use of explicit OpenTelemetry span links instead of hierarchical parent-child trace context nesting in asynchronous message broker consumers and fan-out topologies. Hierarchical span parenting in deferred or batched messaging causes artificial latency inflation and distorts service-dependency DAGs by tying decoupled background job lifetimes to the original publisher trace. Asynchronous consumers MUST initiate root traces or localized parent contexts and link publisher spans via trace links to maintain causal accuracy without violating trace boundary constraints. Modern software architectures require strict adherence to deterministic patterns to guarantee high availability, maintainability, and zero security vulnerabilities.

Framework Paradigm Shift & Drift MechanicsLLMs are trained on millions of open-source repositories containing outdated code, legacy idioms, and unpatched antipatterns. When coding assistants generate implementations for this stack, they default to common statistical tokens: Parenting Asynchronous Message Consumers Directly Under Producer Context Causing Graph Distortion and Artificial Latency Inflation Without an explicit system instruction file, developers spend hours debugging silent failures.
Failure Modes & Production Blast Radius

Hazard Analysis: What Breaks Without This Rule

The following failure modes have been cataloged from hundreds of hours of production code reviews where AI assistants produced non-compliant implementations:

Failure ModeAI Symptom (The Anti-Pattern)SeverityProduction Impact & Remedy
AI Hallucination & Deprecation DriftParenting Asynchronous Message Consumers Directly Under Producer Context Causing Graph Distortion and Artificial Latency InflationCritical
Violating this industrial standard introduces regression bugs, security risks, and unexpected runtime failures in production.
Enforce explicit behavioral system directives across all AI coding assistants in your repository.
Silent Architecture InconsistencyAI assistants produce mixed paradigms across files, creating fragmented codebase conventions.Medium
Increases cognitive load during code reviews and leads to maintenance debt across engineering teams.
Pin project conventions in .cursor/rules, CLAUDE.md, and AGENTS.md so all team agents follow identical guardrails.
Architectural Directives in Detail

Step-by-Step Production Directives

Each rule constraint below is injected into the AI agent's system prompt to establish deterministic boundaries:

1

Engineers MUST extract producer context from message headers and attach it strictly via OpenTelemetry `links` when processing asynchronous queue messages or event streams.

Engineers MUST extract producer context from message headers and attach it strictly via OpenTelemetry `links` when processing asynchronous queue messages or event streams.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
2

Engineers MUST NOT pass the extracted message context as the parent context into `tracer.startActiveSpan()` or `tracer.startSpan()` when handling decoupled or batched asynchronous workloads.

Engineers MUST NOT pass the extracted message context as the parent context into `tracer.startActiveSpan()` or `tracer.startSpan()` when handling decoupled or batched asynchronous workloads.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
3

Consumer spans MUST set `SpanKind.CONSUMER` or `SpanKind.INTERNAL` on the decoupled execution span rather than propagating `SpanKind.SERVER` semantics across asynchronous boundaries.

Consumer spans MUST set `SpanKind.CONSUMER` or `SpanKind.INTERNAL` on the decoupled execution span rather than propagating `SpanKind.SERVER` semantics across asynchronous boundaries.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
4

Batch consumers processing multiple records MUST attach an array of `Link` objects—one corresponding to each message context in the batch—to a single processing span, rather than arbitrarily picking one message as the parent.

Batch consumers processing multiple records MUST attach an array of `Link` objects—one corresponding to each message context in the batch—to a single processing span, rather than arbitrarily picking one message as the parent.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
5

Services MUST capture queue wait time using link attributes (e.g., `messaging.message.envelope.publish_time`) rather than keeping a single distributed span open across queue latency gaps.

Services MUST capture queue wait time using link attributes (e.g., `messaging.message.envelope.publish_time`) rather than keeping a single distributed span open across queue latency gaps.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
Technical Questions & Answers

Frequently Asked Technical Questions

Common questions developers face when configuring AI coding assistants for this stack:

Q:Why is OpenTelemetry Distributed Span Links DAG Causality Standard for Asynchronous Message Fanout critical for AI coding assistants?

Enforces the use of explicit OpenTelemetry span links instead of hierarchical parent-child trace context nesting in asynchronous message broker consumers and fan-out topologies. Hierarchical span parenting in deferred or batched messaging causes artificial latency inflation and distorts service-dependency DAGs by tying decoupled background job lifetimes to the original publisher trace. Asynchronous consumers MUST initiate root traces or localized parent contexts and link publisher spans via trace links to maintain causal accuracy without violating trace boundary constraints. Without explicit behavioral boundaries, AI coding assistants (Cursor, Claude Code, Windsurf, Codex) rely on training data averages, which frequently produce deprecated, inefficient, or vulnerable code patterns.

Q:How does adopting this rule prevent AI hallucinations?

This rule explicitly declares what the AI must avoid (Parenting Asynchronous Message Consumers Directly Under Producer Context Causing Graph Distortion and Artificial Latency Inflation) and prescribes verified positive examples. Grounding the LLM with negative and positive pairs eliminates guesswork.

Q:Which AI coding environments are supported?

This specification is multi-platform compatible: Cursor (.cursor/rules/*.mdc & .cursorrules), Anthropic Claude Code (CLAUDE.md), Windsurf (.windsurfrules), Codex / Cline (AGENTS.md), and GitHub Copilot (.github/copilot-instructions.md).

Q:Can I combine this rule with other technology stacks?

Yes. Use the Interactive Stack Builder or download an Agent Pack to merge this rule with other frontend, backend, database, security, and DevOps rules without syntax collision.

Open Specification · CC BY 4.0·Free for Personal, Team & Commercial In-Repo Use

Citation & Open Source Attribution Guidelines

This specification is licensed under Creative Commons Attribution 4.0 International (CC BY 4.0). You are completely free to adapt and share this rule in your workspace. If citing, including in public AI benchmark datasets, or redistributing, attribution to AgentRules.org is required.

1 Rule in Stack

OpenTelemetry