Story-1463 · pramaan-docs ADR-124 · Agents lane · EPIC-1400 P3 residual

No-parent & malformed traceparent mint X-Ray-format roots, not W3C-random ones

Branch issue-1463-ag-noparent-xray-root · Story: pramaan-io/pramaan-spec#1463 · Sibling: #1439 already proved the parent-EXTRACT path

Why this exists

#1439 proved the happy path: when the broker injects an agent_invoke.v1 meta.traceparent, Atlas joins that trace (first span trace_id == injected parent). It said nothing about the two paths where there is no good parent to join:

In both, Atlas must mint a fresh ROOT. The requirement: that root must be an AWS X-Ray-format trace id — an epoch-prefixed 128-bit id whose top 32 bits are the seconds-since-epoch at mint time — so the trace joins the X-Ray/CloudWatch lane. It must not be a W3C-random id (which would never appear in X-Ray Transaction Search), and a malformed header must never crash the brain or propagate a broken parent.

By construction the dedicated Logfire-lane provider already does this: it is built as TracerProvider(id_generator=AwsXRayIdGenerator()) (observability.py). This ticket makes that test-proven for the orphan/soft-fallback paths and adds live staging evidence. No production code changes — the id-generator was already correct; #1463 is the proof.

What changed

agent_invoke.v1 meta
  NO traceparent            (orphan)            OR   traceparent = "garbage"  (malformed)
  run_id / form_id / firm_id
          |
          v
agent_invoke_observability_context(meta)
  W3C extract: empty carrier -> current ctx     OR   propagator rejects bad header -> no remote parent
  rehydrate baggage allowlist: run_id, form_id  (firm_id NEVER baggage)
          |
          v
dedicated Logfire-lane provider
  TracerProvider(id_generator=AwsXRayIdGenerator())
          |
          v
Pydantic AI opens its library-owned model span
  the trace ROOT has NO parent and an X-Ray-format trace_id (top 32 bits == mint epoch)
  span attrs carry content-free PRAMAAN pivots; NO matter content
SurfaceChange
agents/atlas/tests/test_atlas_observability.pyTwo new tests (orphan + 4 parametrized malformed headers) plus shared helpers. Each builds the dedicated provider the way configure_observability does — same AwsXRayIdGenerator, same content-free span processors — drives a no/bad-parent invoke across the broker→brain thread hop, and asserts the trace ROOT (the one span with no parent) carries an X-Ray-format trace_id.
Production codeNone. The id-generator was already AwsXRayIdGenerator (shipped with #1439). No set_tracer_provider, no new provider, no global ADOT override.

How the test discriminates X-Ray-format from W3C-random

The OTel AwsXRayIdGenerator packs the current epoch seconds into the high 32 bits of the 128-bit trace id (the X-Ray 1-<8 hex epoch>-<24 hex random> shape). A W3C-random generator fills all 128 bits randomly, so its top 32 bits land within a few seconds of "now" with probability ≈ window / 2³² ≈ 1e-7 — effectively never. So the test asserts (trace_id >> 96) ≈ time.time() (±600s). That is a sharp "X-Ray-format, not W3C-random" discriminator. The malformed test additionally asserts no exception, that the root has parent is None (no broken parent propagated), and that the garbage value never leaks into the minted id.

Conformance held intact: firm_id is asserted absent from baggage (a span attribute only), run_id/form_id ride baggage as business keys, and no gen_ai.input.messages/output.messages/system_instructions content reaches the general span.

Staging evidence — no-parent synthetic invoke resolves as an X-Ray trace

A synthetic Atlas invoke was sent to the live staging runtime pramaanAgents_atlas (ap-south-1, v9) with an agent_invoke.v1 envelope carrying no traceparent (and no --trace-parent header). It ran end-to-end (run.started → real DeepSeek turn.delta → turn.completed, HTTP 200).

invoke meta            : { run_id: synthetic-1463-noparent-001, form_id, firm_id }  # NO traceparent
resulting X-Ray trace  : 1-6a3653e8-40a2ae71071829826a76a5a9          # X-Ray Transaction Search (aws/spans) + X-Ray API
trace_id epoch segment : 0x6a3653e8 = 1781945320 = 2026-06-20T08:48:40Z
invoke wall-clock      :          1781945319 = 2026-06-20T08:48:39Z
delta                  : +1s  ->  epoch-prefixed root minted at invoke time (X-Ray-format, NOT W3C-random)
root service / env      : pramaan-agents-atlas · deployment.environment.name=staging · http 200

The trace id's epoch segment decodes to the invoke second, which is the live proof that AWS minted an X-Ray-format root for the no-parent invoke. The brain's POST /invocations SERVER span sits under AgentCore's own ingress span within the same X-Ray trace — i.e. AWS minted the root because the broker supplied no inbound W3C parent, exactly the orphan path under test.

Proof

Verification: ruff check agents/ tests/ scripts/ (clean), pytest tests -q in agents/atlas (204 passed, incl. the new orphan + 4 malformed cases), root pytest tests/ -q -m unit (69 passed), scripts/check_brain_egress.py (clean — raw-tracer + X-Ray + baggage R12 gates green), and the live staging X-Ray trace 1-6a3653e8-… all pass.